Qt http post way "Protocol \"\" is unknown" - qt

void MainWindow::start()
{
QNetworkAccessManager* manager = new QNetworkAccessManager;
QJsonObject obj;
obj.insert("pro", 2005);
obj.insert("id", 10010033);
QNetworkRequest req;
req.setUrl(QUrl("192.168.90.114:38080/udp/data"));
req.setRawHeader("Accept-Encoding", "gzip, deflate");
req.setRawHeader("Content-Type", "application/json");
req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
qDebug() << QJsonDocument(obj).toJson();
manager->post(req, QJsonDocument(obj).toBinaryData());
QObject::connect(manager, &QNetworkAccessManager::finished, [](QNetworkReply* reply)
{
if(reply->error() != QNetworkReply::NoError)
{
qDebug() << "Error:" << reply->errorString();
return;
}
QByteArray buf = reply->readAll();
qDebug() << "OK:"<< buf;
});
}
following is error information
"{\n \"id\": 10010033,\n \"pro\": 2005\n}\n"
Error: "Protocol \"\" is unknown"
when I use postman test this interface, result as following picture

Since I faced the exact same issue, the problem lied in the QUrl part.
I've used QUrl::fromUserInput(address) to fix my issue (someone also suggested ::fromPercentEncoding).

Related

Qt - Cannot read descriptor of the characteristic - BLE

I have a problem with reading characteristic using Bluetooth Low Energy Qt api. The device I'm communicating with is a Decawave DWM1001 module. I was following the tutorial from the documentation. I managed to connect to the device, read and creates it's service successfully. The device has "network node service" with UUID: 680c21d9-c946-4c1f-9c11-baa1c21329e7, which I'm trying to read characteristics from. I call QLowEnergyController::connectToDevice() method, it finds the service and I create a QLowEnergyService object for it, named nodeService.
void BluetoothConnector::serviceDiscovered(const QBluetoothUuid &newService)
{
qDebug() << "Service discovered: " << newService.toString();
if (newService == QBluetoothUuid(nodeServiceUUID)) {
nodeService = controller->createServiceObject(QBluetoothUuid(nodeServiceUUID), this);
if (nodeService) {
qDebug() << "Node service created";
connect(nodeService, &QLowEnergyService::stateChanged, this, &BluetoothConnector::serviceStateChanged);
connect(nodeService, &QLowEnergyService::characteristicChanged, this, &BluetoothConnector::updateCharacteristic);
//connect(nodeService, &QLowEnergyService::descriptorWritten, this, &BLTest::confirmedDescriptorWrite);
nodeService->discoverDetails();
} else {
qDebug() << "Node service not found.";
}
}
}
nodeService is created successfully (I get "Node service created" log), then I connect the signals and slots for the service and then call discoverDetails() on nodeService. The serviceStateChanged() slot looks like this:
void BluetoothConnector::serviceStateChanged(QLowEnergyService::ServiceState newState)
{
if (newState == QLowEnergyService::DiscoveringServices) {
qDebug() << "Discovering services";
} else if (newState == QLowEnergyService::ServiceDiscovered) {
qDebug() << "Service discovered";
const QLowEnergyCharacteristic networkIdChar = nodeService->characteristic(QBluetoothUuid(networkIdUUID));
const QLowEnergyCharacteristic dataModeChar = nodeService->characteristic(QBluetoothUuid(dataModeUUID));
const QLowEnergyCharacteristic locationChar = nodeService->characteristic(QBluetoothUuid(locationUUID));
if (networkIdChar.isValid() && dataModeChar.isValid() && locationChar.isValid()) {
auto idValue = networkIdChar.value();
auto modeValue = dataModeChar.value();
auto locValue = locationChar.value();
qDebug() << "Network ID: " << idValue;
qDebug() << "Mode: " << modeValue;
qDebug() << "Location: " << locValue;
auto notificationDesc = locationChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDesc.isValid()) {
qDebug() << "Notification desc valid";
nodeService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
}
} else {
qDebug() << "Characteristic invalid";
}
}
}
I get the "Discovering services" log and after that the app hangs for a bit and then I get:
"Cannot read descriptor (onDescReadFinished 3): \"{00002902-0000-1000-8000-00805f9b34fb}\" \"{3f0afd88-7770-46b0-b5e7-9fc099598964}\" \"org.freedesktop.DBus.Error.NoReply\" \"Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.\""
"LowEnergy controller disconnected"
"Aborting onCharReadFinished due to disconnect"
It can't read the 00002902-0000-1000-8000-00805f9b34fb which is CCCD descriptor for the 3f0afd88-7770-46b0-b5e7-9fc099598964 characteristic (vendor specific).
Can't figure out what's wrong and why it can't read characteristics from the device. Do I need to do something else to make it work?
Thanks.
---UPDATE---
BluetoothConnector class:
#include "bluetoothconnector.h"
#include <QTimer>
BluetoothConnector::BluetoothConnector(QObject *parent) : QObject(parent)
{
configureDiscoveryAgent();
}
void BluetoothConnector::scan()
{
agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
}
void BluetoothConnector::connectToDevice(QString &addr)
{
auto it = std::find_if(devices.begin(), devices.end(),
[&] (const QBluetoothDeviceInfo& d) { return d.address().toString() == addr; });
if (it == devices.end())
return;
device = *it;
controller = QLowEnergyController::createCentral(device, this);
connect(controller, &QLowEnergyController::serviceDiscovered, this, &BluetoothConnector::serviceDiscovered);
connect(controller, &QLowEnergyController::discoveryFinished, this, &BluetoothConnector::serviceScanDone);
connect(controller, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this, [this](QLowEnergyController::Error error) {
Q_UNUSED(error);
qDebug() << "Controller error: " << error;
emit controllerError();
});
connect(controller, &QLowEnergyController::connected, this, [this]() {
qDebug() << "Controller connected. Search services...";
controller->discoverServices();
});
connect(controller, &QLowEnergyController::disconnected, this, [this]() {
qDebug() << "LowEnergy controller disconnected";
});
controller->connectToDevice();
}
void BluetoothConnector::configureDiscoveryAgent()
{
agent = new QBluetoothDeviceDiscoveryAgent(this);
agent->setLowEnergyDiscoveryTimeout(5000);
connect(agent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothConnector::addDevice);
connect(agent, static_cast<void (QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)>(&QBluetoothDeviceDiscoveryAgent::error),
this, &BluetoothConnector::scanError);
connect(agent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothConnector::scanFinished);
connect(agent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &BluetoothConnector::scanFinished);
}
void BluetoothConnector::addDevice(const QBluetoothDeviceInfo &info)
{
if (!devices.contains(info)) {
qDebug() << "Found device: " << info.name();
devices.append(info);
emit deviceFound(info);
}
}
void BluetoothConnector::scanError(QBluetoothDeviceDiscoveryAgent::Error error)
{
qDebug() << "Scan error: " << error;
}
void BluetoothConnector::scanFinished()
{
emit scanFinishedSignal();
}
void BluetoothConnector::serviceDiscovered(const QBluetoothUuid &newService)
{
qDebug() << "Service discovered: " << newService.toString();
if (newService == QBluetoothUuid(nodeServiceUUID)) {
nodeService = controller->createServiceObject(QBluetoothUuid(nodeServiceUUID), this);
qDebug() << "State: " << nodeService->state();
if (nodeService) {
qDebug() << "Node service created";
connect(nodeService, &QLowEnergyService::stateChanged, this, &BluetoothConnector::serviceStateChanged);
connect(nodeService, &QLowEnergyService::characteristicChanged, this, &BluetoothConnector::updateCharacteristic);
connect(nodeService, &QLowEnergyService::characteristicWritten, this, &BluetoothConnector::characteristicWritten);
connect(nodeService, QOverload<QLowEnergyService::ServiceError>::of(&QLowEnergyService::error),
[=](QLowEnergyService::ServiceError newError){ qDebug() << newError; });
//connect(nodeService, &QLowEnergyService::descriptorWritten, this, &BLTest::confirmedDescriptorWrite);
nodeService->discoverDetails();
} else {
qDebug() << "Node service not found.";
}
}
}
void BluetoothConnector::serviceScanDone()
{
qDebug() << "Services scan done";
}
void BluetoothConnector::characteristicWritten(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
qDebug() << "Characteristic written: " << info.name();
}
void BluetoothConnector::serviceStateChanged(QLowEnergyService::ServiceState newState)
{
qDebug() << "State changed: " << newState;
if (newState == QLowEnergyService::ServiceDiscovered) {
qDebug() << "Service discovered";
const QLowEnergyCharacteristic networkIdChar = nodeService->characteristic(QBluetoothUuid(networkIdUUID));
const QLowEnergyCharacteristic dataModeChar = nodeService->characteristic(QBluetoothUuid(dataModeUUID));
const QLowEnergyCharacteristic locationChar = nodeService->characteristic(QBluetoothUuid(locationUUID));
if (networkIdChar.isValid() && dataModeChar.isValid() && locationChar.isValid()) {
auto idValue = networkIdChar.value();
auto modeValue = dataModeChar.value();
auto locValue = locationChar.value();
qDebug() << "Network ID: " << idValue;
qDebug() << "Mode: " << modeValue;
qDebug() << "Location: " << locValue;
auto notificationDesc = locationChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (notificationDesc.isValid()) {
qDebug() << "Notification desc valid";
nodeService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
}
} else {
qDebug() << "Characteristic invalid";
}
}
}
void BluetoothConnector::updateCharacteristic(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
if (info.uuid() == QBluetoothUuid(networkIdUUID)) {
qDebug() << "Update ID: " << value;
} else if (info.uuid() == QBluetoothUuid(dataModeUUID)) {
qDebug() << "Update mode: " << value;
} else if (info.uuid() == QBluetoothUuid(locationUUID)) {
qDebug() << "Update location: " << value;
}
}
I think, the problem is located on the remote side (your GATT server).
Check the QLowEnergyService::error() and QLowEnergyService::charcteristicWritten() signal and see if you get any response.
What kind of Bluetooth stack you are use on the remote side?
Might be, you don't have the rights to change the CCCD due to a implementation failure. Please check the implementation on the remote side.

Strange reply when uploading zip file to amazon S3 using REST ,QT and PUT request

iam trying to upload zip file to S3 amazon but i have problem.
i am using QT : sending request and receiving reply.
i am sending the URL with zip file here is the code :
QFile *file = new QFile(fileName);
QString fileSize = QString::number(file->size());
file->open(QIODevice::ReadOnly);
QByteArray data(file->readAll());
QNetworkRequest req;
QNetworkReply* rep;
req.setUrl(QUrl(url /*cant post the real URL*/));
req.setRawHeader(QString("Content-Length").toUtf8(), fileSize.toUtf8());
rep = m_manager->post(req, data);
connect(rep, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
CheckReply(rep);
and here is CheckReply function
bool CheckReply(QNetworkReply *reply)
{
if (reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
return false;
}
else
{
qDebug() << reply->header(QNetworkRequest::ContentTypeHeader).toString();
qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toString();
qDebug() << reply->header(QNetworkRequest::ContentLengthHeader).toULongLong();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
return true;
}
}
the problem is , CheckReply() shows this msg : "Error downloading -request URL-".
why this happens , it is upload NOT download.
thanks
OK i find the problem , in case any one face the same problem.
the bug was that i use QUrl(QSting) , to set the request url.
instead of that use this : QUrl::fromEncoded(QByteArray) or
QUrl::fromEncoded(/your QString/.toUtf8()).

QNetworkAccessManager request fail (CA signed certificate)

I've got a CA signed certificate which I use for a webservices. In Chrome and Firefox everything work fine.
Now I want to write a QT-client for the webservice. But all what I get is "connection closed" after 30 seconds. If I request "https://gmail.com" or "https://www.dfn.de/" I get a proper result.
Here is my code.
void Request::send() {
QUrl url("my url");
qDebug() << "URL: " << url;
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, userAgent);
QObject::connect(manager, &QNetworkAccessManager::authenticationRequired, this, &Request::provideAuthenication);
QObject::connect(manager, &QNetworkAccessManager::finished, this , &Request::replyFinished);
QObject::connect(manager, &QNetworkAccessManager::sslErrors, this , &Request::sslErrors);
qDebug() << "fire request";
manager->get(request);
}
void Request::provideAuthenication(QNetworkReply *, QAuthenticator *ator) {
qDebug() << "provideAuthenication";
ator->setUser("***");
ator->setPassword("***");
}
void Request::replyFinished(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError)
qDebug() << "Network Error: " << reply->errorString();
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute );
QVariant statusPhrase = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute );
qDebug() << "Result: " << statusCode.toInt() << " " << statusPhrase.toString();
qDebug() << "Data: " << reply->readAll();
}
void Request::sslErrors(QNetworkReply *, const QList<QSslError> &errors) {
foreach (const QSslError &error, errors) {
qDebug() << "SSL Error: " << error.errorString();
}
}
And that is the output. No sslError! No HTTP Error!
URL: QUrl( "my url" )
Network Error: "Connection closed"
Result: 0
Data: ""
So why hangs QT or the server? Did I miss something?!
It was a misconfiguration of openjdk7 (glassfish).
The hint of Aldaviva works on serverfault for me. https://serverfault.com/questions/389197/ssl-routinesssl23-writessl-handshake-failure
To bad that QT do not throw an ssl-error.

Reusing ASIO connection, read_some exception

I am currently trying to figure out how to properly reuse an asio socket. I am able to successfully send out a request, and get the result. The second time I send out a request, I get an exception: read_some: End of file. The second write seems to work fine, I see the second http request going out over wireshark. I am thinking that there is left over information on the socket that is corrupting my connection in some way. Any help would be appreciated with this issue. Here is the code I am using:
persistent_connection::persistent_connection(std::string ip, std::string port):
io_service_(), socket_(io_service_), is_setup_(false)
{
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(ip,port);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ip::tcp::endpoint endpoint = *iterator;
socket_.async_connect(endpoint, boost::bind(&persistent_connection::handler_connect, this, boost::asio::placeholders::error, iterator));
io_service_.run();
}
void persistent_connection::handler_connect(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(ec)
{
std::cout << "Couldn't connect" << ec << std::endl;
return;
}
else
{
boost::asio::socket_base::keep_alive keep_option(true);
socket_.set_option(keep_option);
}
}
void persistent_connection::write(std::string message)
{
std::string request_stream = "GET /" + message + " HTTP/1.0\r\n";
request_stream += "HOST: 10.1.10.220";
request_stream += "Accept: */*\r\n";
request_stream += "Connection: keep-alive\r\n\r\n";
try
{
boost::asio::write(socket_, boost::asio::buffer(request_stream, request_stream.size()));
}catch(std::exception& e)
{
std::cout << "Write exception: " << e.what() << std::endl;
}
boost::array<char,8192> buf;
try
{
socket_.read_some(boost::asio::buffer(buf));
}catch(std::exception& e)
{
std::cout << "Read exception: " << e.what() << std::endl;
}
std::string response = buf.data();
std::cout << response << std::endl;
}
Edit: Added main function.
int main()
{
persistent_connection p("10.1.10.220", "80");
std::string check;
do
{
std::cin >> check;
if(check.compare("s") == 0)
{
std::cout << "Sending" << std::endl;
p.write("100");
}
}while(check.compare("x") != 0);
}
The fact you get this exception when trying to read_some means that the HTTP server closes the connection after the first request is over, i.e. the server ignores "Connection: keep-alive" header (note that HTTP 1.0 servers don't necessarily support persistent connections).
However, in 1.1 version connections are persistent by default, so requesting "HTTP/1.1" should solve this issue.

QOauth::Interface for twitter API

I am trying to get authentification to twitter's API using QOAuth.
my code currently is :
oauthInterface->setConsumerKey(CONSUMER_KEY);
oauthInterface->setConsumerSecret(CONSUMER_SECRET_KEY);
oauthInterface->setRequestTimeout(10000);
QOAuth::ParamMap reply = oauthInterface->requestToken("https://api.twitter.com/oauth/request_token", QOAuth::GET, QOAuth::HMAC_SHA1);
if(oauthInterface->error() == QOAuth::NoError)
{
token = reply.value(QOAuth::tokenParameterName());
tokenSecret = reply.value(QOAuth::tokenSecretParameterName());
qDebug() << "temporary token" << token << tokenSecret;
}
reply = oauthInterface->accessToken("https://api.twitter.com/oauth/access_token",QOAuth::GET, token, tokenSecret, QOAuth::HMAC_SHA1);
if(oauthInterface->error() == QOAuth::NoError)
{
qDebug() << "final token" << reply.value("screen_name") << reply.value(QOAuth::tokenParameterName()) << reply.value(QOAuth::tokenSecretParameterName());
}
else
{
qDebug() << "ERROR" << oauthInterface->error();
}`
And gives me
temporary token "cBhxmmdkYgmghyy02kmfc0VSIuykRCNoQRh2h1r3Yg" "oYF8b2lzPSgDTRku8X4BjjnoVw5dAXXZBXc2R9P8Jk"
ERROR 401
Using QOAuth::POST instead of QOAuth::GET I have the same result
How am I to get access token's using QOAuth ?
As I managed to solve my own probleme I post here the solution :
The fact is, for beeing granted access to https://api.twitter.com/oauth/access_token you need a pin which can be obtained by the user at https://api.twitter.com/oauth/authenticate
Hewever you can only get this pin if you set oauth_callback=oob when asking for temporary tokens at https://api.twitter.com/oauth/request_token
I finaly ended up with the following code :
oauthInterface->setConsumerKey(CONSUMER_KEY);
oauthInterface->setConsumerSecret(CONSUMER_SECRET_KEY);
oauthInterface->setRequestTimeout(10000);
QOAuth::ParamMap args;
args.insert("oauth_callback", "oob");
QOAuth::ParamMap reply = oauthInterface->requestToken("https://api.twitter.com/oauth/request_token", QOAuth::POST, QOAuth::HMAC_SHA1, args);
if(oauthInterface->error() == QOAuth::NoError)
{
token = reply.value(QOAuth::tokenParameterName());
tokenSecret = reply.value(QOAuth::tokenSecretParameterName());
qDebug() << "temporary token" << token << tokenSecret;
}
QString url = "https://api.twitter.com/oauth/authenticate";
url.append("?");
url.append(QOAuth::tokenParameterName() + "=" + token);
QDesktopServices::openUrl(QUrl(url));
QOAuth::ParamMap args2;
QString pin = QInputDialog::getText(this, "Pin", "Enter pin");
args2.insert("oauth_verifier", pin.toAscii()); //pin.toAscii());
reply = oauthInterface->accessToken("https://api.twitter.com/oauth/access_token", QOAuth::GET, token, tokenSecret, QOAuth::HMAC_SHA1, args2);
if(oauthInterface->error() == QOAuth::NoError)
{
qDebug() << "final token" << reply.value("screen_name") << reply.value(QOAuth::tokenParameterName()) << reply.value(QOAuth::tokenSecretParameterName());
}
else
{
qDebug() << "ERROR" << oauthInterface->error();
}

Resources