curlpp response is doubled - c++

I'm just new to curlpp but I can't see what's wrong here with my code, so I hope someone can help me out.
I'm using curlpp in C++ to make Facebook Graph queries. That means the Facebook server will return Json data as result.
My code looks as follows:
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>
...
curlpp::Easy myRequest;
bool error = false;
QString result = "";
try {
// Setting the URL to the Facebook server with the query
curlpp::options::Url myUrl(request->getURL().toStdString());
// Creating stream for the result
std::ostringstream os;
curlpp::options::WriteStream ws(&os);
// setting my opts: url and output stream
myRequest.setOpt(myUrl);
myRequest.setOpt(ws);
// perform the request
myRequest.perform();
// stream the result into my stream
os << myRequest;
result = QString::fromStdString(os.str());
} catch (curlpp::RuntimeError &e) {
error = true;
qWarning() << "Error in HttpRequest execution:" << e.what();
} catch (curlpp::LogicError &e) {
error = true;
qWarning() << "Error in HttpRequest execution:" << e.what();
} catch (...) {
error = true;
qWarning() << "Unknown error in HttpRequest execution.";
}
My problem now is that the resulting stream (and thus my result QString) do contain the Json object sent by the Facebook Graph server, but twice.
That means, directly two times the same object, one after the other. And that makes it invalid Json.
But that can not be what the server delivers. And it's not what I get when I do check it with the openssl command line tool and make a HTTP Get request on my own.
What's wrong with my code?
Best, Michael

Related

QNetworkReply returning incomplete XML data

I'm sending a HTTP GET request to a remote server. Using various parameters I define the content I'm interested in. In particular I make sure that output=xml is in the query since it makes the server return a reply as XML.
I have the following connections between my class HttpRetriever and the respective QNetworkReply and QNetworkAccessManager (for the QNetworkRequest see slotStartRequest()):
connect(this->reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
SLOT(slotErrorRequest(QNetworkReply::NetworkError)));
connect(this->reply, &QNetworkReply::finished, this, &HttpRetriever::slotFinishRequest);
connect(this->manager, &QNetworkAccessManager::finished, this->reply, &QNetworkReply::deleteLater);
connect(this->reply, &QIODevice::readyRead, this, &HttpRetriever::slotReadyReadRequest);
The slots that are of interest here have the following declaration:
slotFinishRequest():
void HttpRetriever::slotFinishRequest()
{
LOG(INFO) << "Finishing HTTP GET request from URL \"" << this->url.toString() << "\"";
this->reply = Q_NULLPTR;
// Reset validity of reply from a previous request
this->validReply = false;
// Skip validation if it's disabled
if (!this->validateReply)
{
LOG(WARNING) << "Validation disabled. In order to enable it see the \"validate\" and \"validationMode\" in \"settings.ini\"";
this->validReply = true;
}
else
{
// Validate reply
this->validReply = validateReply();
}
if (!this->validReply)
{
return;
}
processReply(); // Parsing
this->processingRequest = false;
}
slotReadyReadRequest():
void HttpRetriever::slotReadyReadRequest()
{
LOG(INFO) << "Received data from \"" << this->url.toString() << "\"";
this->bufferReply = this->reply->readAll();
}
Inside the slotFinishRequest() I call the processReply():
void HttpRetriever::processReply()
{
LOG(INFO) << "Processing reply for request \"" << this->url.toString() << "\"";
LOG(DEBUG) << QString(this->bufferReply);
// Process the XML from the reply and extract necessary data
QXmlStreamReader reader;
reader.addData(this->bufferReply);
// Read the XML reply and extract required data
// TODO
while (!reader.atEnd())
{
LOG(DEBUG) << "Reading XML element";
reader.readNextStartElement();
QXmlStreamAttributes attributes = reader.attributes();
foreach (QXmlStreamAttribute attrib, attributes)
{
LOG(DEBUG) << attrib.name();
}
}
if (reader.hasError())
{
LOG(ERROR) << "Encountered error while parsing XML data:" << reader.errorString();
}
LOG(INFO) << "Sending data to data fusion handler";
// TODO
}
I trigger the HTTP get request through the following slot:
void HttpRetriever::slotStartRequest(quint32 id)
{
if (this->processingRequest)
{
this->reply->abort();
}
this->processingRequest = false;
// The first request also instantiates the manager. If the slot is called after the instance of HafasHttpRetriever
// is moved to a new thread this will ensure proper parenting
if (!this->manager)
{
this->manager = new QNetworkAccessManager(this);
}
quint32 requestId = generateRequestId(stopId);
if (!this->url.hasQuery())
{
LOG(WARNING) << "Attempting to start request without parameters";
}
// Part of the filters applied to the request to reduce the data received (for more see slotSetRequestParams())
QUrlQuery query(this->url.query());
query.addQueryItem("input", QString::number(requestId));
// TODO Add more filters; see documentation
this->url.setQuery(query);
LOG(INFO) << "Requesting data from \"" << this->url.toString() << "\" with request ID:" << requestId;
QNetworkRequest request(this->url);
this->reply = this->manager->get(request);
// Establish connections from/to the reply and the network access manager
connect(this->reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
SLOT(slotErrorRequest(QNetworkReply::NetworkError)));
connect(this->reply, &QNetworkReply::finished, this, &HttpRetriever::slotFinishRequest);
connect(this->manager, &QNetworkAccessManager::finished, this->reply, &QNetworkReply::deleteLater);
connect(this->reply, &QIODevice::readyRead, this, &HttpRetriever::slotReadyReadRequest);
}
As you can see so far I have laid down the foundation for the network communication between my class and the server and I am yet to start working on the parsing of the XML reply and extracting the information I need from it.
The problem is that I am getting (very, very often) either
Encountered error while parsing XML data: Start tag expected.
or
Encountered error while parsing XML data: Premature end of document
in my processReply() function. This happens every time I get a large reply (a couple of hundreds up to a couple of thousands of lines). It never happens when I get a small one (30-40 lines give or take).
So the issue is obviously somewhere in the amount of data I am receiving, the way it is put together by the QNetworkAccessManager (or whichever Qt component in all this buffers the received chunks of data) and/or perhaps the way I have setup the instances of the network-related components in my class. I also have to make an important note here namely that in my browser (latest Firefox with the HttpRequester add-on) I am always receiving the complete XML no matter how large it is. So this seems to be a problem exclusive to my application and has nothing to do with the network settings on my system.
Since #Marco didn't write the answer...
The problem was that I was rewriting my buffer all the time by assigning the result from QNetworkReply::readAll(). As suggested using QByteArray::append() solves the problem.
In order to prevent a possible issue from this solution namely that you keep appending with each and every next reply you get, QByteArray::clear() needs to be called at some point for example when the finished() signal is emitted. Of course one needs to first process its contents before flushing it down the drain.

How to transfer a C++ object to a web service using POCO library

I have an image processing application that uses Qt and openCV.
for each frame, I should send the captured cv::Mat image object to the server to process it and get the results.
I should use the REST architecture for its low playload.
What is the tool that I should use to send cv::Mat to the server.
I am using POCO for portability.
I seek for the lightest solution to do that, I need a minimum speed of 10 frames processed by the server in a second.
I mean, is there a method to pass the C++ Object to the server without an explicit serialization?
EDIT
With the POCO library, you can take a look in this answer: HttpRequest PUT content in poco library. He is sending a file on a ifstream.
In this answer you can check how to convert a cv::Mat into a istream: OpenCV cv::Mat to std::ifstream for base64 encoding.
And finally, Thanks to polymorphism, the istream is implicity converted to a ifstream.
You can use the C++ Rest SDK. A code example of the PUT command.
Source of code
Library Github where you can find the full documentation.
#include <http_client.h>
#include <filestream.h>
#include <iostream>
#include <sstream>
using namespace web::http;
using namespace web::http::client;
// Upload a file to an HTTP server.
pplx::task<void> UploadFileToHttpServerAsync()
{
using concurrency::streams::file_stream;
using concurrency::streams::basic_istream;
// To run this example, you must have a file named myfile.txt in the current folder.
// Alternatively, you can use the following code to create a stream from a text string.
// std::string s("abcdefg");
// auto ss = concurrency::streams::stringstream::open_istream(s);
// Open stream to file.
return file_stream<unsigned char>::open_istream(L"myfile.txt").then([](pplx::task<basic_istream<unsigned char>> previousTask)
{
try
{
auto fileStream = previousTask.get();
// Make HTTP request with the file stream as the body.
http_client client(L"http://www.fourthcoffee.com");
return client.request(methods::PUT, L"myfile", fileStream).then([fileStream](pplx::task<http_response> previousTask)
{
fileStream.close();
std::wostringstream ss;
try
{
auto response = previousTask.get();
ss << L"Server returned returned status code " << response.status_code() << L"." << std::endl;
}
catch (const http_exception& e)
{
ss << e.what() << std::endl;
}
std::wcout << ss.str();
});
}
catch (const std::system_error& e)
{
std::wostringstream ss;
ss << e.what() << std::endl;
std::wcout << ss.str();
// Return an empty task.
return pplx::task_from_result();
}
});
/* Sample output:
The request must be resent
*/
}

halt while sending email with Poco Net

I'm trying to send an email using the Poco Net library with this code (my credentials are arbitrary obviously):
void send_email() {
// Poco::Net::SMTPClientSession session("localhost", 465);
const std::string& smtp_host {"mail.example.com"};
const std::string& smtp_user {"marinos#example.com"};
const std::string& smtp_passwd {"myPassword"};
std::string to = "marinos#example.com";
std::string from = "marinos#example.com";
std::string subject = "Your first e-mail message sent using Poco Libraries";
subject = Poco::Net::MailMessage::encodeWord(subject, "UTF-8");
std::string content = "Well done! You've successfully sent your first message using Poco SMTPClientSession";
Poco::Net::MailMessage message;
message.setSender(from);
message.addRecipient(Poco::Net::MailRecipient{Poco::Net::MailRecipient::PRIMARY_RECIPIENT, to});
message.setSubject(subject);
message.setContentType("text/plain; charset=UTF-8");
message.setContent(content, Poco::Net::MailMessage::ENCODING_8BIT);
try {
Poco::Net::SMTPClientSession session(smtp_host, 465);
session.open(); // this is where it halts
try {
session.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, smtp_user, smtp_passwd);
session.sendMessage(message);
std::cout << "Message successfully sent" << std::endl;
session.close();
} catch (Poco::Net::SMTPException& e) {
std::cerr << e.displayText() << std::endl;
session.close();
}
} catch (Poco::Net::NetException& e) {
std::cerr << e.displayText() << std::endl;
}
}
and my program simply halts. I've used a debugger to locate the problem and it seems that the program halts when calling session.open(). Am I doing something wrong here?
Since I do not know specification of your SMTP server, I am speculating that you're probably suppose to use SMTPS instead of plain SMTP, because port 465 is default port for SMTPS (according to Wikipedia). I guess the program halts during SSL handshaking. By looking into Poco documentation I see that there exists SSL version of the Poco::Net::SMTPClientSession. Thus, you should try with SecureSMTPClientSession. Check if your mail server requires START_TLS, in that case I guess you should additionally call bool startTLS().

POCO json POST_METHOD returns results but gives I/O exception and ends program

Hi im havng a problem with poco under linux, im making a https json post to a webserver and im getting the response as i expected.
The problem is that i get an error after the response is printed and it ends the execution of my program.
Here is what i get on console:
200 OK
"{\"test_results\": ["result1", "result2", "result3", "result4"]}"
terminate called after throwing an instance of 'Poco::IOException' what(): I/O error
Here is the code that make the above result to be printed:
int posTry(){
try
{
// prepare session
Poco::Net::Context::Ptr context = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
Poco::URI uri("https://someURL/somePATH");
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(), context);
// prepare path
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
// send request
std::string test = "{Some json code to get results that is already working}";
Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST, path, Poco::Net::HTTPMessage::HTTP_1_1);
req.setContentType("application/json");
req.setKeepAlive(true);
req.setContentLength( test.length() );
session.sendRequest(req) << test;
// get response
Poco::Net::HTTPResponse res;
std::cout << res.getStatus() << " " << res.getReason() << std::endl;
// print response
std::istream &is = session.receiveResponse(res);
Poco::StreamCopier::copyStream(is, std::cout);
std::vector<Poco::Net::HTTPCookie> cookies;
res.getCookies( cookies );
}
catch( const Poco::Exception& e )
{
std::cerr << e.displayText() << std::endl;
}
catch (...)
{
std::cout << "error";
return -1;
}
return 0;
}
I don't know what is this error about and I can't even catch the error in (...) and make the program continue. Can someone help me?
The exception comes from the destructor of Poco::Net::HTTPSClientSession,
This is a known bug fixed in POCO release 1.4.2.
source: http://pocoproject.org/docs/99100-ReleaseNotes.html
If you cannot upgrade, you should be able to get rid of the exception by adding a specific catch for it.

Casablanca webserver gives seemingly random error

I am using the Casablanca REST SDK to make a webservice. The webservice has the client pass JSON through the URL and processes it. However in some cases if I send JSON that contains an array, it will crash the service. The strange part is the handler method that actually handles the JSON runs all the way through and ends before the error is given. My main function is:
int main()
{
std::string ip;
std::string port;
std::ifstream inputStream;
inputStream.open("ip_port.config");
while(!inputStream.eof())
{
inputStream >> ip;
inputStream >> port;
}
inputStream.close();
std::string uri = "http://"+ip+":"+port+"/";
//set up URL
web::http::uri u(U(uri));
//set up listener for URL
web::http::experimental::listener::http_listener listener(u);
listener.support(methods::GET, handle_get);
try
{
pplx::task<void> l = listener.open();
while(true)
{
l.wait();
sleep(1);
}
listener.close().wait();
}
catch(int e)
{
std::stringstream errorMessage;
errorMessage << "Error: " << e;
logRequest(errorMessage.str(), "Error Message");
}
return 0;
}
I have put two prints: "Beginning of Handler" and "End of Handler" in the handle_get function, which are both printed, leading me to beleive that the cause of the error has something to do with the while loop with the listener, but the error it gives has nothing to do with the listener:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Im trying to wrap my head around what about the listener could return that error.