QNetworkAccessManager is not sending data part of POST request - qt

When sending POST data to server, from Qt application looks everything good but data part of HTTP part were not sent. In Wireshark in POST packet is visible correct "Content-Length" value but size of whole HTTP segment is only about 226 bytes (is independent on POST data size).
I can't find reason why data part is not send. Any idea?
The application is running in console. A complete source is below.
project.pro:
QT += widgets
QT -= gui
QT += network
CONFIG += c++11
TARGET = POSTrequest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
main.cpp:
#include <QObject>
#include <QApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QNetworkRequest request(QUrl("http://www.server.com/index.php"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkAccessManager manager;
QNetworkReply *reply = manager.post(request, "a=aaaaaa");
QObject::connect(reply, SIGNAL(finished()), &a, SLOT(quit()));
return a.exec();
}

This works for me on both OS X and Windows:
#post-request-36549732.pro
QT = core network
CONFIG += console c++11
CONFIG -= app_bundle
TARGET = post-request-36549732
TEMPLATE = app
SOURCES += main.cpp
// main.cpp
#include <QtNetwork>
int main(int argc, char ** argv)
{
QCoreApplication a{argc, argv};
QNetworkAccessManager manager;
QByteArray post{"a="};
post.append(QByteArray{512, 'b'});
QNetworkRequest req(QUrl("http://server/test.php"));
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
// Must be a queued connection, or else the multi-threaded manager might
// win the race and signal quit before `a.exec()` starts running. In such
// case, the `quit()` is a NOP. We don't want that.
QObject::connect(&manager, &QNetworkAccessManager::finished, &a, [](QNetworkReply * reply){
qDebug() << reply->errorString();
qApp->quit();
}, Qt::QueuedConnection);
manager.post(req, post);
return a.exec();
}
You might be interpreting your Wireshark data incorrectly. Make sure you're looking at the Reassembled TCP aspect of the HTTP request. Here's how it looks for me; server is 192.168.2.1:

Related

How to authenticate with GitHub using Qt and Access Token

I try to implement GitHub authentication from my Qt application using Access Token. I can connect to GitHub using Postman without any problem by providing URL (in my case this is https://api.github.com/notifications) and access token I've generated on the GitHub (Settings/Developer settings/Personal access tokens) https://github.com/settings/tokens. Now I want to do the same using Qt but can't find examples how to do that. There is example for Reddit( https://doc.qt.io/qt-5/qtnetworkauth-redditclient-example.html) in the Qt documentation but it uses some redirect algorithm, not access token:
auto replyHandler = new QOAuthHttpServerReplyHandler(1337, this);
oauth2.setReplyHandler(replyHandler);
oauth2.setAuthorizationUrl(QUrl("https://www.reddit.com/api/v1/authorize"));
oauth2.setAccessTokenUrl(QUrl("https://www.reddit.com/api/v1/access_token"));
I have no clue how to do the same using provided Access Token.
If you are going to use the personal token then it is not necessary to implement the OAuth/OAuth2 logic since the first part of the transaction is to obtain the token but the OP already has it. If you have the token then it is only necessary to request the rest API:
#include <QByteArray>
#include <QCoreApplication>
#include <QJsonDocument>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const QString username = "<username>";
const QString token = "<token>";
const QByteArray basic_authorization = QByteArray("Basic ") + (username + ":" + token).toUtf8().toBase64();
QNetworkRequest request;
request.setRawHeader(QByteArrayLiteral("Authorization"), basic_authorization);
QUrl url("https://api.github.com/notifications");
request.setUrl(url);
QNetworkAccessManager manager;
QNetworkReply *reply = manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, [reply](){
QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
qDebug() << doc;
QTimer::singleShot(1000, &QCoreApplication::quit);
});
return a.exec();
}

Get SO_RCVBUF socket option value from Qt

I want to get the value of the SO_RCVBUF socket option used by Qt to be sure that it uses by default the system value (that I changed).
But the following piece of code returns an "Invalid" QVariant:
QUdpSocket socket;
qDebug() << socket.socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption);
Does it mean that the socketOption() Qt method only get the value if it has been set with setSocketOption()?
Or did I make a mistake?
In order to obtain the socket information, then the native socket must have been created, that is, obtain a socketDescriptor() other than -1, but in your case it is not connected causing that value not to be read, returning a invalid QVariant.
The solution is to connect the socket and analyze that the socket is valid to obtain the desired information:
#include <QCoreApplication>
#include <QTimer>
#include <QUdpSocket>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QUdpSocket socket;
QObject::connect(&socket, &QAbstractSocket::stateChanged, [&socket](){
if(socket.socketDescriptor() != -1){
qDebug() << socket.socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption);
// kill application
QTimer::singleShot(1000, &QCoreApplication::quit);
}
});
socket.bind(QHostAddress::LocalHost, 1234);
return a.exec();
}
Output:
QVariant(int, 212992)

Intellisense for QDialog object in Qt Console application

I'd like to show and then close a dialog after 5 seconds within my main() function in a Qt Console application. Here is my code that works:
Main.cpp:
#include <QApplication>
#include "splash.h"
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// some stuff to do
Splash splash;
QTimer::singleShot(5000, &splash, SLOT(close()));
splash.exec();
// some more stuff to do
exit(0);
// return a.exec();
}
text_console.pro:
QT += widgets \
gui
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp \
splash.cpp
FORMS += \
splash.ui
HEADERS += \
splash.h
The above code complies and works, but I do not get complete intellisense for the splash object (e.g. setModal(), exec()). What am I doing wrong?
I am using Qt5 in linux.

Qt QNetworkAccessManager & simple web service return

I have a simple web service with the following URL:
http://localhost:8080/WebSvc1/webresources/generic/data?ctype=Ping
This returns a simple XML data:
<CALL TYPE='Ping'><IP>10.0.0.10</IP></CALL>
I'm trying to write a Qt program to call this web service.
The code that makes the call is below:
QUrl qrl("http://localhost:8080/WebSvc1/webresources/generic/data?ctype=Ping");
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
printf ("Calling url: [%s]\n", qPrintable(url));
QNetworkReply *reply = 0;
reply = manager->get(QNetworkRequest(qrl));
qDebug() << reply->readAll();
I'm expecting/hoping the readAll will get the XML text data and print it (via qDebug).
Instead I see nothing and the program just hangs.
UPpdate, also have this:
void obj::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->readAll();
}
I've included an example (forcing a synchronous request <-> reply exchange to easy the debugging process) that should work for you:
QUrl qrl("http://localhost:8080/WebSvc1/webresources/generic/data?ctype=Ping");
qDebug() << "Calling url: " << qrl.toString();
manager = new QNetworkAccessManager();
QNetworkReply* reply = manager->get(QNetworkRequest(qrl));
QEventLoop eventLoop;
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
if (reply->error() != QNetworkReply::NoError)
{
qDebug() << "Network error: " << reply->error();
}
else
{
qDebug() << reply->readAll();
}
Notice that the "emitter" of the finished signal is not the QNetworkAccessManager but the reply itself.
I think your error could be with your web service. I tried your code out (slightly modified) with httpbin.org, and was getting proper replies. Maybe take a look at your code with httpbin.org and then see if you can track down what's wrong with your service.
MainWindow.cpp
#include "MainWindow.hpp"
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QDebug>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent), manager(this) {
load();
}
void MainWindow::load() {
const QUrl url(QStringLiteral("http://httpbin.org/xml"));
QNetworkReply* reply = manager.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
replyFinished(reply);
});
qDebug() << reply->readAll(); // The reply won't be ready by now, so
// testing here isn't very helpful.
}
void MainWindow::replyFinished(QNetworkReply* reply) {
qDebug() << reply->readAll();
reply->deleteLater();
}
MainWindow.hpp
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
public slots:
void load();
void replyFinished(QNetworkReply* reply);
private:
QNetworkAccessManager manager;
};
#endif // MAINWINDOW_HPP
main.cpp
#include "MainWindow.hpp"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
network.pro
QT += core gui widgets network
TARGET = network
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11
SOURCES += \
main.cpp \
MainWindow.cpp
HEADERS += MainWindow.hpp

QNetworkManager uploading file to FTP crash

I am trying to upload a simple test text file to a FTP server. In order to achieve this I am using QNetworkAccessManager, since QFtp has been deprecated in Qt 5.1.
I created a test.txt file in the programs directory and using QFile I am opening it as QIODevice::ReadWrite | QIODevice::Text.
The problem is when I set the connection and tell the QNetworkAccessManager to upload a file the program crashes ("FTPConnectionTest does not respond"). It happens both when I am trying to use an external FTP server or a local one created with FileZilla.
I connected all signals emitted by the reply (functions: uploadFinish, uploadProgress, uploadError) however no feedback is beeing captured.
Question: Is this problem lying on the side of FTP server or am I doing something wrong in my code?
Code snipped below:
Main.cpp
#include <QCoreApplication>
#include <ftp.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Ftp ftp;
return a.exec();
}
ftp.cpp
#include "ftp.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QFile>
#include <QUrl>
#include <QDebug>
Ftp::Ftp()
{
QFile file("test.txt");
if (file.open(QIODevice::ReadWrite | QIODevice::Text)) {
url = QUrl("ftp://127.0.0.1/test.txt");
url.setUserName("user");
url.setPassword("password");
qDebug() << "URL set" << url;
QNetworkAccessManager* nam = new QNetworkAccessManager();
qDebug() << "nam set";
QNetworkReply *rep = nam->put(QNetworkRequest(url), &file);
qDebug() << "after rep";
connect(rep, SIGNAL(finished()), this, SLOT(uploadFinish()));
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(uploadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
}
else qDebug() << "failed to open";
}
void Ftp::uploadFinish()
{
qDebug() << "finished uploading file";
}
void Ftp::uploadProgress(qint64 a, qint64 b)
{
qDebug() << a << "/" << b;
}
void Ftp::uploadError(QNetworkReply::NetworkError state)
{
qDebug() << "State" << state;
}
See the QNetworkAccessManager::put documentation:
data must be opened for reading when this function is called and must remain valid until the finished() signal is emitted for this reply.
Your file object falls out of scope when the constructor finishes execution, so QNetworkAccessManager probably tries to read from object that is already deleted. You need to make file a class member variable or create it using QFile* file = new QFile().

Resources