QNetworkReply has no data - c++

I have a QWebView where I'm watching the network requests by connecting:
QObject::connect(page()->networkAccessManager(),
SIGNAL(finished(QNetworkReply*)),
this,
SLOT(networkLoaded(QNetworkReply*)));
then:
void browserControl::networkLoaded(QNetworkReply *reply)
{
const QUrl reqUrl = reply->request().url();
qDebug() << "url = " << reqUrl;
QByteArray array = reply->readAll();
QString data = QString::fromUtf8(array.data(), array.size());
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).value<int>();
qDebug() << "data = " << data;
qDebug() << "http code = " << statusCode;
}
But data is always empty, not matter if statusCode is 200. browserControl class is inheried from QWebView class.

You get no data because QWebPage read all data before your slot is called

Related

QNetworkRequest causes memory corruption

I created a library which will handle all HTTP requests and parsing of response data in JSON format. When I called the method that includes get request in my main application (with GUI), I received a memory corruption error. So I added QEventLoop and a timer to wait for the response before proceeding to other processes. I was able to get the response data by calling QNetworkReply.readall(). I needed to get the char* value of the response data so I called the QNetworkReply.data() but it is empty. Why?
Here are the codes I wrote:
Library which handles HTTP requests:
void HttpRequest::getRequest(string param1, string param2)
{
pManager_ = new QNetworkAccessManager(this);
QUrl cUrl(sampleUrl);
QNetworkRequest request(cUrl);
request.setRawHeader(keyHeader.c_str(), param1.c_str());
connect(pManager_, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
connect(pManager_, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> & )), this,
SLOT(handleSslErrors(QNetworkReply*, const QList<QSslError> & )));
cUrl.addQueryItem("name", QString::fromStdString(param2));
pManager_->get(request); // memory corruption error encountered in main application after calling this
std::cout << "after calling get" << std::endl;
}
void HttpRequest::requestFinished(QNetworkReply *pReply)
{
QByteArray responseData;
std::cout << " request finished" << std::endl;
int responseStatus = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
std::cout << " status code: " << responseStatus << std::endl;
if(pReply->error())
std::cout << " Error: " << pReply->errorString().toStdString() << std::endl;
else
{
responseData = pReply->readAll();
qDebug() << " Response data: " << responseData;
const char* pResponseData = responseData.data();
qDebug() << "pResponseData: " << pResponseData ;
// parsing here
}
pReply->deleteLater();
pManager_->deleteLater();
}
void HttpRequest::handleSslErrors(QNetworkReply *pReply, const QList<QSslError> & )
{
std::cout << " SSL ERROR" << std::endl;
int responseStatus = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
}
Main GUI application:
DialogTest::DialogTest(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogTest)
{
// some codes here
if(enabled)
{
HttpRequest::instance()->getInformation(param1, param2); // memory corruption happened here when I called getRequest() method with no event loop
}
// other threads here
}
Here is the code that uses QEventLoop:
void HttpRequest::getRequest(string param1, string param2)
{
QTimer qTimer;
QEventLoop loop;
pManager_ = new QNetworkAccessManager(this);
QUrl cUrl(sampleUrl);
QNetworkRequest request(cUrl);
request.setRawHeader(keyHeader.c_str(), param1.c_str());
connect(&qTimer,SIGNAL(timeout()),&loop, SLOT(quit()));
connect(pManager_, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
QNetworkReply *pReply = pManager_->get(request);
qTimer.start(1000);
loop.exec();
int responseCode = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
std::cout << "status code: " << responseCode << std::endl;
if(pReply->error())
{
std::cout << " Error: " << pReply->errorString().toStdString() << std::endl;
}
else
{
qDebug() << "[HttpRequest] Response data: " << pReply->readAll();
QByteArray response = pReply->readAll(); // it printed this value: "{"count":3,"codes":["x00000A","x00000B","x00000C"]}" which is correct
char* pResponseData = response.data();
qDebug() << "pResponseData: " << pResponseData ; //it printed this: pResponseData:
}
delete pReply;
delete pManager_;
}
I am expecting this response data from a HTTP get command:
"{"count":3,"codes":["x00000A","x00000B","x00000C"]}"
Problem:
What is the best way to implement this? I want to put all HTTP request in a library then call it my main application with GUI. Please note that:
When I use QEventLoop inside the library to wait for the response, QNetworkReply.data() is empty. I need the value of QNetworkReply.data() for parsing.
When I did not use QEventLoop and use signal and slot alone (as shown in the code above), memory corruption occurred in main application after executing HTTP get command. No response data is received.
an advice:
never use a direct delete for a QObject. BAD:
delete pReply;
delete pManager_;
Qt way,GOOD:
pReply->deleteLater();
pManager->deleteLater();
Better: no "new" (dynamic memory)
QNetworkAccessManager Manager_;
...
connect(&Manager_, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
..
pReply->deleteLater();

QTcpSocket not Receiving Data Sent from Server

I'm having trouble sending data from a server to a client using Qt. Whenever I do QTcpSocket::waitForBytesWritten() after a call to QTcpSocket::write(...), it returns false.
I tried using the bytesWritten signal, but that never gets emitted, presumably because no data is able to be written, and no data is received on the client side.
The writeData method is what is being called in the MainWindow class, but to try and narrow down the cause of the problem, I moved the writing of data to the client into the newConnection method.
The message Connection received is printed to the output window. I'm sending the string Some random data in the newConnection method to the client for testing purposes, but this is not being received by the client (the code to output the received data on the client side is inside Character::readData() method).
The value of the returnValue variable is true, and the code returns from the call to the client->waitForBytesWritten(-1) method. client->errorString() gives Unknown error, and then the message Bytes written is printed (even though, evidently, nothing is written, but I'm just using it as a status message).
Server.cpp
#include "Server.h"
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
qDebug() << connect(server, SIGNAL(newConnection()), SLOT(newConnection()));
qDebug() << connect(server, SIGNAL(bytesWritten()), SLOT(bytesWritten()));
qDebug() << "Listening:" << server->listen(QHostAddress::Any, 1451);
server->waitForNewConnection(-1);
}
void Server::newConnection()
{
qDebug("Connection received");
client = server->nextPendingConnection();
client->write("Some random data\n");
bool returnValue = client->flush();
qDebug() << "Return value: " << returnValue;
qDebug() << client->waitForBytesWritten(-1);
qDebug() << "Error: " << client->errorString();
qDebug() << "Bytes written";
}
void Server::bytesWritten(qint64 bytes)
{
qDebug() << "Bytes written: " << QString::number(bytes);
}
void Server::writeData(std::string data)
{
QByteArray byteArray = QByteArray(data.c_str());
qDebug() << "Write data: " << QString::fromStdString(data);
client->write(byteArray);
}
Client.cpp
#include "Client.h"
#include "mainwindow.h"
Client::Client(QObject* parent) : QObject(parent)
{
socket = new QTcpSocket(this);
(void)QObject::connect(socket, SIGNAL(connected()), this, SLOT(connected()));
qDebug() << "Connect signal" << QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
bool Client::connectToHost(QString host)
{
socket->connectToHost(host, 1451);
socket->waitForConnected();
qDebug() << "Error: " << QString::number(socket->error() == QAbstractSocket::UnknownSocketError);
return true;
}
void Client::connected()
{
qDebug("Socket is connected");
qDebug() << QString::number(socket->state() == QAbstractSocket::ConnectedState);
}
void Client::readData()
{
qDebug("Read data");
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
QByteArray data = sender->readAll();
std::string character = data.toStdString();
qDebug() << "Character received: " << QString::fromStdString(character);
MainWindow::characterReceived(character);
}

QJsonDocument to list or array in c++

I've tried this code and works, but I didn't understand how can get json and convert in array or list with Qt.
My code:
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QNetworkRequest req(QUrl(QString("http://myurljson.com/getjson")));
QNetworkReply *reply = mgr.get(req);
eventLoop.exec(); // blocks stack until "finished()" has been called
if (reply->error() == QNetworkReply::NoError) {
QString strReply = (QString)reply->readAll();
qDebug() << "Response:" << strReply;
QJsonDocument jsonResponse = QJsonDocument::fromJson(strReply.toUtf8());
QJsonObject jsonObj = jsonResponse.object();
qDebug() << "test:" << jsonObj["MCC_Dealer"].toString();
qDebug() << "test1:" << jsonObj["MCC_User"].toString();
delete reply;
}
else {
//failure
qDebug() << "Failure" <<reply->errorString();
delete reply;
}
my json get (3 records from url):
[{"MCC_Dealer":'test',"MCC_User":'test',"CurrentDealer":'test',"CurrentUser":'test'},{"MCC_Dealer":'test',"MCC_User":'test',"CurrentDealer":'test',"CurrentUser":'test'},{"MCC_Dealer":'test',"MCC_User":'test',"CurrentDealer":'test',"CurrentUser":'test'}]
I need to get json and set in list or in array.
My target is convert json response in array or list with c++ and Qt.
Any ideas?
Thanks
As I have mentioned in my comments, your JSON response is already an array, so you don't need to create additional structures to store the data you got. In order to de-serialize your data you can do the following:
[..]
QJsonArray jsonArray = jsonResponse.array();
for (auto it = jsonArray.constBegin(); it != jsonArray.constEnd(); ++it)
{
const QJsonValue &val = *it;
// We expect that array contains objects like:
// {"MCC_Dealer":'test',"MCC_User":'test',"CurrentDealer":'test',"CurrentUser":'test'}
QJsonObject o = val.toObject();
// Iterate over all sub-objects. They all have string values.
for (auto oIt = o.constBegin(); oIt != o.constEnd(); ++oIt)
{
// "MCC_Dealer":'test'
qDebug() << "Key:" << oIt.key() << ", Value:" << oIt.value().toString();
}
}

Can not read received data from QNetworkAccessManager::finished slot when received data is large [duplicate]

I want to see the results of a GET request. By my understanding, this code should do it. What am I doing wrong?
void getDoc::on_pushButton_2_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.google.com")));
}
void getDoc::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->error(); //prints 0. So it worked. Yay!
QByteArray data=reply->readAll();
qDebug() << data; // This is blank / empty
QString str(data);
qDebug() << "Contents of the reply: ";
qDebug() << str; //this is blank or does not print.
}
The code compiles and runs fine. It just doesn't work.
Try modifying your replyFinished slot to look like this:
QByteArray bytes = reply->readAll();
QString str = QString::fromUtf8(bytes.data(), bytes.size());
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
You can then print the statusCode to see if you are getting a 200 response:
qDebug() << QVariant(statusCode).toString();
If you are getting a 302 response, you are getting a status redirect. You will need to handle it like this:
if(statusCode == 302)
{
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "redirected from " + replyUrl + " to " + newUrl.toString();
QNetworkRequest newRequest(newUrl);
manager->get(newRequest);
return;
}
I'm returning when encountering a status code of 302 since I don't want the rest of the method to execute.
I hope this helps!

Qt QNetworkReply is always empty

I want to see the results of a GET request. By my understanding, this code should do it. What am I doing wrong?
void getDoc::on_pushButton_2_clicked()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://www.google.com")));
}
void getDoc::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->error(); //prints 0. So it worked. Yay!
QByteArray data=reply->readAll();
qDebug() << data; // This is blank / empty
QString str(data);
qDebug() << "Contents of the reply: ";
qDebug() << str; //this is blank or does not print.
}
The code compiles and runs fine. It just doesn't work.
Try modifying your replyFinished slot to look like this:
QByteArray bytes = reply->readAll();
QString str = QString::fromUtf8(bytes.data(), bytes.size());
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
You can then print the statusCode to see if you are getting a 200 response:
qDebug() << QVariant(statusCode).toString();
If you are getting a 302 response, you are getting a status redirect. You will need to handle it like this:
if(statusCode == 302)
{
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "redirected from " + replyUrl + " to " + newUrl.toString();
QNetworkRequest newRequest(newUrl);
manager->get(newRequest);
return;
}
I'm returning when encountering a status code of 302 since I don't want the rest of the method to execute.
I hope this helps!