Retrieve file sent through post request in c++ - c++

I'm setting up a micro-service for a cpp application, and i need to send a post request with a file as a parameter from a js project to the cpp one through this micro-service, i've been able to send the post request but i can't retrieve the file.
I've tried to use "http_response.extract-string/json" but it doesn't work, the result is empty
void MicroserviceController::handlePost(http_request message) {
std::cout<< "handlePost(http_request message) " << std::endl;
std::cout<< message.to_string() << std::endl;
std::cout<< message.extract_json().get() << std::endl;
std::ofstream o("hello.json");
o << message.extract_json().get()<< std::endl;
after running that, i got an empty hello file.
I'm sure there is a simple solution to this, i just have a lack in http_request methods .
Thanks in advance for your help.

Related

Unable to deserialize flatbuf messages received through TCP

I am trying to serialize, then deserialize a FlatBuf object.
I am using FlatBuffer 1.10.0. I want to send the serialized data through TCP to another process, but at the moment I am not able to deserialize it even in the same function.
The fbs file:
table StringPacket
{
type:int;
logLevel:int;
myAge:int;
stringdata:string;
}
root_type StringPacket;
The code in C++:
...
uint8_t * packet_data;
int data_size;
using namespace flatbuffers;
FlatBufferBuilder fbb;
//serialize the string data
auto thisStringData = fbb.CreateString(m_stringdata);
//create the packet (I tried thisway too)
//auto packet = CreateStringPacket(fbb, 2, 3, 27, thisStringData);
StringPacketBuilder strbuilder(fbb);
strbuilder.add_logLevel(3);
strbuilder.add_myAge(4);
strbuilder.add_type(1);
strbuilder.add_stringdata(fbb.CreateString("somehing"));
auto thisPacket = strbuilder.Finish();
packet_data = fbb.GetBufferPointer();
data_size = fbb.GetSize();
auto get = GetStringPacket(packet_data);
std::cout << "Deserialized Log level: " << get->logLevel()<<std::endl;
std::cout << "Des Age: " << get->myAge() << std::endl;
...
I get an unhandled exception of 0xC0000005, Access violation reading location...
at the line:
std::cout << "Deserialized Log level: " << get->logLevel()<<std::endl;
Or anytime when I call a function of the 'get' object.
What am I doing wrong? How can I correctly deserialize it?
Please make sure you test with asserts on (in "debug" mode), as it would have answered your questions already. In particular:
You are calling GetBufferPointer on an unfinished buffer (which normally asserts). You need to call fbb.Finish(thisPacket) or similar.
You are calling CreateString inside a table builder (which normally asserts), and you create a string outside of it which you don't use. Presumably you had intended to call strbuilder.add_stringdata(thisStringData) instead.

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 get new added files in a folder using Inotify along with libev?

My program (in C++) uses libev event loop. And I need to watch on a specific folder (say foo) for new files.
I cannot use Inotify::WaitForEvents() in block mode because I do not want to block my libev event loop. As suggested in inotify documentation,I use Inotify::SetNonBlock(true) to make it non-block. The inotify file descriptor is then passed to libev EV_STAT to watch on (as suggested in libev documentation).
The libev callback for EV_STAT is indeed called when there are new files in the folder foo. However, when I use Inotify::WaitForEvents() followed by Inotify::GetEventCount(), I get zero event.
I suspect that libev already consumed the event and convert it to EV_STAT event. If this is the case, how can I get the names of those new files?
I knew there is inode number in EV_STAT callback parameters, but getting file name from inode number is not trivial. So it is better if I can get file name instead.
Any suggestions?
EDIT
I wrote a small program to reproduce this problem. It seems the events are not lost. Instead, inotify events do not come yet when libev callback is called. The event can re-appear when you copy in a new file.
The program to reproduce the issue:
#include <ev++.h>
#include "inotify-cxx.h"
#include <iostream>
const char * path_to_watch = "/path/to/my/folder";
class ev_inotify_test
{
InotifyWatch m_watch;
Inotify m_notify;
// for watching new files
ev::stat m_folderWatcher;
public:
ev_inotify_test() : m_watch(path_to_watch, IN_MOVED_TO | IN_CLOSE_WRITE),
m_notify()
{
}
void run()
{
try {
start();
// run the loop
ev::get_default_loop().run(0);
}
catch (InotifyException & e) {
std::cout << e.GetMessage() << std::endl;
}
catch (...) {
std::cout << "got an unknown exception." << std::endl;
}
}
private:
void start()
{
m_notify.SetNonBlock(true);
m_notify.Add(m_watch);
m_folderWatcher.set<ev_inotify_test, &ev_inotify_test::cb_stat>(this);
m_folderWatcher.set(path_to_watch);
m_folderWatcher.start();
}
void cb_stat(ev::stat &w, int revents)
{
std::cout << "cb_stat called" << std::endl;
try {
m_notify.WaitForEvents();
size_t count = m_notify.GetEventCount();
std::cout << "inotify got " << count << " event(s).\n";
while (count > 0) {
InotifyEvent event;
bool got_event = m_notify.GetEvent(&event);
std::cout << "inotify confirm got event" << std::endl;
if (got_event) {
std::string filename = event.GetName();
std::cout << "test: inotify got file " << filename << std::endl;
}
--count;
}
}
catch (InotifyException &e) {
std::cout << "inotify exception occurred: " << e.GetMessage() << std::endl;
}
catch (...) {
std::cout << "Unknown exception in inotify processing occurred!" << std::endl;
}
}
};
int main(int argc, char ** argv)
{
ev_inotify_test().run();
}
When I copy in a tiny file (say 300 bytes), the file is detected immediately. But if I copy a bigger file (say 500 kB), there is no event until I copy another file in and then I get two events.
The output looks like:
cb_stat called # test_file_1 (300 bytes) is copied in
inotify got 1 event(s).
inotify confirm got event
test: inotify got file test_file_1
cb_stat called # test_file_2 (500 KB) is copied in
inotify got 0 event(s). # no inotify event
cb_stat called # test_file_3 (300 bytes) is copied in
inotify got 2 event(s).
inotify confirm got event
test: inotify got file test_file_2
inotify confirm got event
test: inotify got file test_file_3
I finally figured out the problem: I should use ev::io to watch the file descriptor of inotify, instead of using ev::stat to watch the folder.
In the example code, the definition of m_folderWatcher should be:
ev::io m_folderWatcher;
instead of
ev::stat m_folderWatcher;
And it should be initialized as:
m_folderWatcher.set(m_notify.GetDescriptor(), ev::READ);
instead of
m_folderWatcher.set(path_to_watch);

QuickFix error: 58=Conditionally Required Field Missing (268)

This is the server config file
[DEFAULT]
ConnectionType=acceptor
SocketAcceptPort=5001
SocketReuseAddress=Y
StartTime=00:00:00
EndTime=00:00:00
FileLogPath=log
FileStorePath=store
[SESSION]
BeginString=FIX.4.4
SenderCompID=EXECUTOR
TargetCompID=CLIENT1
DataDictionary=/home/idf/Documents/quickfixspec/spec/FIX44.xml
I have a FIXServer and FIXClient quickfix application. The client on connection immediately shows:
IN: 8=FIX.4.4|9=197|35=X|34=34|49=EXECUTOR|52=20141114-19:12:07.219|56=CLIENT1|55=bond3|110=0|268=1|269=0|270=100.272681729868|271=0|278=1862140492|279=0|6350=0|6351=0|6360=0.0528078713919967|6361=0.00698885442689061|10=158
OUT: 8=FIX.4.4|9=123|35=j|34=45|49=CLIENT1|52=20141114-19:12:07.220|56=EXECUTOR|45=34|58=Conditionally Required Field Missing(268)|372=X|380=5|10=139
The server shows:
IN: 8=FIX.4.4|9=123|35=j|34=46|49=CLIENT1|52=20141114-19:12:12.220|56=EXECUTOR|45=35|58=Conditionally Required Field Missing (268)|372=X|380=5|10=137
OUT: 8=FIX.4.4|9=193|35=X|34=36|49=EXECUTOR|52=20141114-19:12:17.221|56=CLIENT1|268=1|279=0|269=0|278=500257692|55=bond|5270=99.54393400065|6271=0|110=0|6350=0|6351=0|6360=0.0107738308608532|6361=0.047250702092424|10=154
I looked this up on http://www.fixtradingcommunity.org/FIXimate/FIXimate3.0/ and it is "Number of entries in Market Data message."
It looks like the server is sending Marketdata and not specifying the number of NoMDEntries? It is a bit strange, because for the Java version anyway, it appears this field gets set automatically, e.g., http://www.quickfixj.org/quickfixj/usermanual/1.5.3/usage/repeating_groups.html
This is the line that causes the problem in the client as it is getting MarketData from the server. I added the try catch block so I could see the exception myself, but it gives less information than if I let QF handle the exception and sending it back to the server through [OUT:]
void MyApplication::fromApp( const FIX::Message& message, const FIX::SessionID& sessionID )
throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{
std::cout << std::endl << "IN: " << message << std::endl;
try
{
crack( message, sessionID );
}
catch(std::exception& ex)
{
//I suppose I could comment out FIX::FieldNotFound above in the throw clause and ignore this exception
/// here since it seems that the thing is plain wrong since the field IS there!!??
std::cout << "crack exception: " << ex.what() << "\n";
}
}

Duplicate events received from POCO DirectoryWatcher

I'm trying to use the DirectoryWatcher class from POCO's file system library to monitor a specific folder for changes. The code is pretty simple and looks like this:
Monitor::Monitor() {
pattern = new Glob("/path/to/dir/*.dat",
Glob::GLOB_DOT_SPECIAL);
watcher = new DirectoryWatcher(std::string("/path/to/dir"));
watcher->itemAdded += delegate(this, &Monitor::onFileAdded);
watcher->itemModified += delegate(this, &Monitor::onFileChanged);
}
void Monitor::onFileAdded(const DirectoryWatcher::DirectoryEvent& addEvent) {
if (pattern->match(addEvent.item.path())) {
std::cout << "File added: " << addEvent.item.path() << std::endl;
}
}
void Monitor::onFileChanged(const DirectoryWatcher::DirectoryEvent& changeEvent) {
if (pattern->match(changeEvent.item.path())) {
std::cout << "File changed: " << changeEvent.item.path() << std::endl;
}
}
I'm observing some odd behavior. If I copy a new version of a file over a file that's already in the watched folder, I receive the 'item changed' notification twice. If I open a file that's already in the watched folder, edit its contents and save it, I receive an 'item added' notification followed by an 'item changed' notification.
This is on Ubuntu Linux 14.04 and ext4 file system with POCO 1.4.6p2.
Has anyone else observed similar behavior? Could this be related to some specific characteristic of my machine and the OS/file system combo? Is it possible to filter the unwanted events somehow?
Thanks in advance.