cpprestsdk handler class crashes when using STL container as member - c++

I wrote a simple code using cpprestsdk. I use a map (records) as a member of CommandHandler class, and manipulate it in a public method (has_record()).
it works before handler.open().wait() runs, but when I call it in a request, it crashes!
Here is my code:
#define BOOST_DATE_TIME_NO_LIB
#include <string>
#include <vector>
#include <cpprest/uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/asyncrt_utils.h>
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
class CommandHandler
{
public:
CommandHandler(utility::string_t url);
pplx::task<void> open() { return m_listener.open(); }
pplx::task<void> close() { return m_listener.close(); }
bool has_record();
private:
std::map< std::string, unsigned int > records;
void handle_get_or_post(http_request message);
http_listener m_listener;
};
bool CommandHandler::has_record()
{
return records.size() > 0 && records.find("1") != records.end();
}
CommandHandler::CommandHandler(utility::string_t url) : m_listener(url)
{
m_listener.support(methods::GET, std::bind(&CommandHandler::handle_get_or_post, this, std::placeholders::_1));
m_listener.support(methods::POST, std::bind(&CommandHandler::handle_get_or_post, this, std::placeholders::_1));
}
void CommandHandler::handle_get_or_post(http_request request)
{
if(this->has_record())
request.reply(status_codes::OK, 1);
else
request.reply(status_codes::OK, 0);
};
int main(int argc, char** argv)
{
try
{
utility::string_t address = U("http://127.0.0.1:9595");
uri_builder uri(address);
auto addr = uri.to_uri().to_string();
CommandHandler handler(addr);
if(handler.has_record())
std::cout<<"work!";
handler.open().wait();
ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
ucout << U("Press ENTER key to quit...") << std::endl;
std::string line;
std::getline(std::cin, line);
handler.close().wait();
}
catch (std::exception& ex)
{
ucout << U("Exception: ") << ex.what() << std::endl;
ucout << U("Press ENTER key to quit...") << std::endl;
std::string line;
std::getline(std::cin, line);
}
return 0;
}

I found the problem but I don't understand why it throws. The problem is in this line of code:
request.reply(status_codes::OK, 0);
That 0 throws an exception

Related

POST request body is empty (cpp-netlib 0.13.0)

I have upgraded cpp-netlib from v0.11.0 to 0.13.0 and run into some difficulties.
Previously, when a request was sent to the server, the body of the request could be read from the request object.
The request body is now empty when I send the same request to a server using v0.13.0.
The rest of the request object appears to be correct - only the body is empty.
Is there something I need to do differently? I can't find any examples on the site that show how the body is extracted.
I have confirmed the same behaviour from the hello world example.
#include <boost/network/protocol/http/server.hpp>
#include <iostream>
namespace http = boost::network::http;
struct hello_world;
typedef http::server<hello_world> server;
struct hello_world
{
void operator()(const server::request &request, server::connection_ptr connection)
{
///////////////////////////////////
// request.body is empty
///////////////////////////////////
server::string_type ip = source(request);
unsigned int port = request.source_port;
std::ostringstream data;
data << "Hello, " << ip << ':' << port << '!';
connection->set_status(server::connection::ok);
connection->write(data.str());
}
};
int main(int argc, char *argv[]) {
try {
hello_world handler;
server::options options(handler);
server server_(options.address("192.168.0.19").port("9999"));
server_.run();
}
catch (std::exception &e) {
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
Here is the request I'm sending:
curl -v -X POST http://192.168.0.19:9999/my-app/rest/foo/1.0/bar -H 'Content-Type: application/x-www-form-urlencoded' --data key=value
In older versions of cpp-netlib you could choose between a sync_server and a async_server class. Since version 0.12 only the async_server class is available. This class does not read body data of a POST request into request.body automatically, but requires the user to read the data in an asynchronous way using connection->read(callback).
Long story short, I've compiled a minimal echo server example that shows how to do this correctly. It also explains how to deal with the not well known Expect: 100-continue header that might be involved.
Please check out echo_async_server.cpp which has been added to the repo recently.
#include <vector>
#include <boost/config/warning_disable.hpp>
#include <boost/network/include/http/server.hpp>
#include <boost/network/utils/thread_pool.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
namespace net = boost::network;
namespace http = boost::network::http;
namespace utils = boost::network::utils;
struct async_hello_world;
typedef http::async_server<async_hello_world> server;
struct connection_handler : boost::enable_shared_from_this<connection_handler> {
connection_handler(server::request const &request)
:req(request), body("") {}
~connection_handler() {
std::cout << "connection_handler dctor called!" << std::endl;
}
void operator()(server::connection_ptr conn) {
int cl;
server::request::headers_container_type const &hs = req.headers;
for(server::request::headers_container_type::const_iterator it = hs.begin(); it!=hs.end(); ++it) {
if(boost::to_lower_copy(it->name)=="content-length") {
cl = boost::lexical_cast<int>(it->value);
break;
}
}
read_chunk(cl, conn);
}
void read_chunk(size_t left2read, server::connection_ptr conn) {
std::cout << "left2read: " << left2read << std::endl;
conn->read(
boost::bind(
&connection_handler::handle_post_read,
connection_handler::shared_from_this(),
_1, _2, _3, conn, left2read
)
);
}
void handle_post_read(
server::connection::input_range range, boost::system::error_code error, size_t size, server::connection_ptr conn, size_t left2read) {
if(!error) {
std::cout << "read size: " << size << std::endl;
body.append(boost::begin(range), size);
size_t left = left2read - size;
if(left>0) {
read_chunk(left, conn);
} else {
//std::cout << "FINISHED at " << body.size()<< std::endl;
}
}
std::cout << "error: " << error.message() << std::endl;
}
void handle_post_request(server::connection_ptr conn)
{
std::cout << "handle request..." << std::endl;
std::cout << "post size: " << body.size() << std::endl;
}
server::request const &req;
std::string body;
};
struct async_hello_world {
void operator()(server::request const &request, server::connection_ptr conn) {
boost::shared_ptr<connection_handler> h(new connection_handler(request));
(*h)(conn);
}
void error(boost::system::error_code const & ec) {
// do nothing here.
std::cout << "async error: " << ec.message() << std::endl;
}
};
int main(int argc, char * argv[]) {
utils::thread_pool thread_pool(4);
async_hello_world handler;
server instance("0.0.0.0", "1935", handler, thread_pool);
instance.run();
return 0;
}
You need to read manually the body. Now a connection_ptr object is used and a handler must be attached for doing the read.
So it must look something like this:
if (r.method == "POST") {
auto foundIt = std::find_if(r.headers.begin(), r.headers.end(),
[](auto const & h) { return h.name == "Content-Length"; });
if (foundIt == r.headers.end())
throw std::logic_error("No Content-Length header found in POST");
auto handleReadFunc = [this](auto &&... args) {
this->handleReadBody(args...);
};
//This attaches a callback to read the body
connection->read(handleReadFunc);
}

How can I run miltiple ServerApplications with POCO C++?

I've started learning POCO C++ library and I'm stuck while trying to run 2 servers in the same application (so that they can use some common runtime variables). These are 2 different servers, one of them is TCP TimeServer and the other one is simple UDP EchoServer. The code:
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::TCPServer;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class TimeServerConnection : public TCPServerConnection
{
public:
TimeServerConnection(const StreamSocket& s, const std::string& format) :
TCPServerConnection(s),
_format(format)
{
}
void run()
{
Application& app = Application::instance();
bool isOpen = true;
Poco::Timespan timeOut(10, 0);
unsigned char incommingBuffer[1000];
app.logger().information("SYSLOG from " + this->socket().peerAddress().toString());
while (isOpen) {
if (socket().poll(timeOut, Poco::Net::Socket::SELECT_READ) == false) {
std::cout << "TIMEOUT!" << std::endl << std::flush;
} else {
int nBytes = -1;
try {
nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer));
std::cout << incommingBuffer << std::endl;
} catch (Poco::Exception& exc) {
std::cerr << "Network error: " << exc.displayText() << std::endl;
isOpen = false;
}
if (nBytes == 0) {
std::cout << "Client closes connection!" << std::endl << std::flush;
isOpen = false;
} else {
std::cout << "Receiving nBytes: " << nBytes << std::endl << std::flush;
}
}
}
try
{
Timestamp now;
std::string dt(DateTimeFormatter::format(now, _format));
dt.append("\r\n");
socket().sendBytes(dt.data(), (int)dt.length());
}
catch (Poco::Exception& exc)
{ app.logger().log(exc); }
}
private:
std::string _format;
};
class TimeServerConnectionFactory : public TCPServerConnectionFactory
{
public:
TimeServerConnectionFactory(const std::string& format) :
_format(format)
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{ return new TimeServerConnection(socket, _format); }
private:
std::string _format;
};
class UDPServer : public Poco::Util::ServerApplication
{
public:
UDPServer(){}
~UDPServer(){}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize() { ServerApplication::uninitialize(); }
int main(const std::vector<std::string>& args)
{
unsigned short port = (unsigned short)config().getInt("udpport", 9002);
std::cout << "[UDP] Using port " << port << std::endl;
std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));
Poco::Net::SocketAddress socketaddress(Poco::Net::IPAddress(), 9001);
Poco::Net::DatagramSocket datagramsocket(socketaddress);
char buffer[1024]; // 1K byte
while (1) {
Poco::Net::SocketAddress sender;
int n = datagramsocket.receiveFrom(buffer, sizeof(buffer) - 1, sender);
buffer[n] = '\0';
std::cout << sender.toString() << ":" << buffer << std::endl;
}
return 0;
}
};
class TimeServer : public Poco::Util::ServerApplication
{
public:
TimeServer() : _helpRequested(false)
{
}
~TimeServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A server application that serves the current date and time.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
unsigned short port = (unsigned short)config().getInt("tcpport", 9911);
std::cout << "Using port " << port << std::endl;
std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));
ServerSocket svs(port);
TCPServer srv(new TimeServerConnectionFactory(format), svs);
srv.start();
std::cout << "Server started!\n";
waitForTerminationRequest();
srv.stop();
std::cout << "Server stopped!\n";
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char** argv)
{
TimeServer app;
UDPServer app2;
app.run(argc, argv);
app2.run(argc, argv);
}
In the end of code I have int main() method where I'm trying to run 2 servers. However I get assertion violation here. There is a similar question on StackOverflow, however boost is used there while I'm using plain C++, so that solution is not relevant to me.
How can I run simultaneously these 2 servers?
ServerApplication was not designed for multiple instances. What you should do is run one ServerApplication and launch TCPServer and UDPServer in that application.
Actually if you want to made like this (as you question), seperated both
tcp (a) class and
udp (b) class.
Call both in other class (c) and
define which one
(c) -> (a)
(c) -> (b)
u need to call first and when. So u need make condition and decision.
Note: give them space time before run to made poco breath. 😂

cpprest client receive no response

when i build my own cpprestsdk server and client,i found that when my server receive a request and reply to it, my client have no reaction to it,and it never goes into the breakpoint where i handle the http_response,here is my code;
i was stuck for so many days,will someone help me fix this,thanks a lot
(client send request,server receives it and reply, client fail to receive http_response)
Server(i just got it from somewhere on internet):
#include "cpprest/json.h"
#include "cpprest/http_listener.h"
#include "cpprest/uri.h"
#include "cpprest/asyncrt_utils.h"
#include "cpprest/http_client.h"
using namespace web::http::experimental::listener;
using namespace web::http;
using namespace web;
void handle_get(http_request message)
{
message.reply(status_codes::OK, U("Hello, World!"));
};
void handle_post(http_request message)
{
message.reply(status_codes::NotFound);
};
void handle_put(http_request message)
{
message.reply(status_codes::NotFound);
};
void handle_delete(http_request message)
{
message.reply(status_codes::NotFound);
};
#define TRACE(msg) std::wcout << msg
#define TRACE_ACTION(a, k, v) std::wcout << a << L" (" << k << L", " << v << L")\n"
int main(int argc, char ** argv)
{
uri_builder uri(U("http://localhost:8888"));
http_listener listener(uri.to_uri());
listener.support(methods::GET, handle_get);
listener.support(methods::POST, handle_post);
listener.support(methods::PUT, handle_put);
listener.support(methods::DEL, handle_delete);
try
{
listener
.open()
.then([&listener](){TRACE(L"\nstarting to listen\n"); })
.wait();
while (true);
}
catch (std::exception const & e)
{
std::wcout << e.what() << std::endl;
}
catch (...)
{
std::wcout << "Unknown exception" << std::endl;
}
return 0;
}
and here is my Client
#include "cpprest/http_client.h"
#include "cpprest/filestream.h"
using namespace utility; // Common utilities like string conversions
using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams
int main(int argc, char* argv[])
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.html")).then([=](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
http_client client(U("http://www.bing.com/"));
http_client localclient(U("http://localhost:8888"));
return localclient.request(methods::GET);
})
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
system("pause");
return response.body().read_to_end(fileStream->streambuf());
})
.then([=](size_t)
{
return fileStream->close();
});
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
system("pause");
}
return 0;
}

Boost Signals2 tracking

I am using Boost Signals2 in one of our project.In this I want automatic connection management,for this I am testing Boost Signals2 tracking but I am not getting slot invoked.
After I run following code , slots are not called .
Environment:
VS 2010,windows 7,boost 1.54
#include <stdio.h>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/shared_ptr.hpp>
typedef boost::signals2::signal<void ()> signal_test;
using namespace boost;
class SubjectTest
{
public:
void Connect(const signal_test::slot_type &subscriber)
{
m_Signal.connect(subscriber);
std::cout << "No of connections : " << m_Signal.num_slots() << std::endl;
}
void Notify()
{
m_Signal();
}
private:
signal_test m_Signal;
};
class Listner
{
public:
Listner(){}
~Listner(){}
Listner(std::string name)
:m_name(name)
{
}
void GotSignal()
{
std::cout << m_name << std::endl;
}
void ConnectWithTracking(SubjectTest *s)
{
shared_ptr<Listner> l = new Listner();
s->Connect(signal_test::slot_type(&Listner::GotSignal,l.get()).track(l));
}
void ConnectNormal(SubjectTest *s)
{
s->Connect(bind(&Listner::GotSignal,this));
}
private:
std::string m_name;
shared_ptr<Listner> l;
};
void main()
{
Listner l2("First");
SubjectTest sub;
try
{
l2.ConnectWithTracking(&sub);
//l2.ConnectNormal(&sub);
sub.Notify();
{
Listner l3("Second");
l3.ConnectWithTracking(&sub);
//l3.ConnectNormal(&sub);
sub.Notify();
}
sub.Notify();
}
catch(std::exception ex)
{
std::cout << ex.what() << std::endl;
}
std::cout << "Finish" <<std::endl;
}
Updated :
*Working now*
#include <stdio.h>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/shared_ptr.hpp>
typedef boost::signals2::signal<void ()> signal_test;
using namespace boost;
class SubjectTest
{
public:
void Connect(const signal_test::slot_type &subscriber)
{
m_Signal.connect(subscriber);
std::cout << "No of connections : " << m_Signal.num_slots() << std::endl;
}
void Notify()
{
m_Signal();
}
private:
signal_test m_Signal;
};
class Listner : public boost::enable_shared_from_this<Listner>
{
public:
Listner(){}
~Listner(){}
Listner(std::string name)
:m_name(name)
{
}
void GotSignal()
{
std::cout << m_name << std::endl;
}
void ConnectWithTracking(SubjectTest *s)
{
s->Connect(signal_test::slot_type(&Listner::GotSignal,shared_from_this().get()).track(shared_from_this()));
}
void ConnectNormal(SubjectTest *s)
{
s->Connect(bind(&Listner::GotSignal,this));
}
private:
std::string m_name;
};
void main()
{
shared_ptr<Listner> l2(new Listner("First"));
SubjectTest sub;
try
{
l2->ConnectWithTracking(&sub);
sub.Notify();
{
shared_ptr<Listner> l3(new Listner("Second"));
l3->ConnectWithTracking(&sub);
//l3.ConnectNormal(&sub);
sub.Notify();
}
sub.Notify();
}
catch(std::exception ex)
{
std::cout << ex.what() << std::endl;
}
std::cout << "Finish" <<std::endl;
}
Now this is complete example of Signal2 Automatic Connection Management
{
shared_ptr<Listner> l(new Listner());
s->Connect(signal_test::slot_type(&Listner::GotSignal,l.get()).track(l));
}
In the above lines l pointee gets destroyed at the closing } - meaning that the slot you just connected got expired.
The whole point of tracking is to pass to track() a shared_ptr (or weak_ptr), which is bound (or tightly related) to the slot itself. It doesn't make sense to pass a shared_ptr whose lifespan is unrelated to that of the slot itself.

how printing exception by a class function that contains the string to print?

I have this:
catch (Except& e) {
std::cout << e.print() << std::endl;
}
I want this to print: OK you won!
so I have the class:
class Except{
public:
std::string print() {
std::string error("OK you won!\n");
return error;
}
};
I have this error in the Except class: "'string' in namespace 'std' does not name a type"
You have to include the header for std::string : #include <string>
You're probably not throwing it right - works for me:
#include <iostream>
#include <string>
class Except{
public:
std::string stack() {
std::string error("OK you won!\n");
return error;
}
};
int main() {
try {
throw Except();
} catch (Except& e) {
std::cout << e.stack() << std::endl;
}
return 0;
};
Output:
OK you won!
Check the code below:
#include <iostream>
#include <string>
class Except{
public:
std::string stack() {
std::string error("OK you won!\n");
return error;
}
};
int main() {
try {
throw Except();
} catch (Except &e) {
std::cout << e.stack() << std::endl;
}
return 0;
}
The output is:
./a.out
OK you won!