Qt or libcurl c++: Facebook api POST request to image upload - c++

Good day. I can't understend how create a POST request to upload an image. I was searching in the net, and found several versions. But is always response for me (after request) - "(# 324) Requires upload file".
Thank you!
ui->webView->load(QUrl("https://www.facebook.com/dialog/oauth?"
"client_id=XXXXXXXXXX&"
"display=popup&"
"response_type=token&"
"scope=user_status,user_photos,publish_actions&"
"redirect_uri=https://www.facebook.com/connect/login_success.html"));
1
QString uploadUrl = "https://graph.facebook.com/me/photos?access_token=" +
accessToken;
QString photoPath = QCoreApplication::applicationDirPath() + "/image_example.png";
QFileInfo fileInfo(photoPath);
QFile file(photoPath);
QString comment = "User provided message";
QString bound="---------------------------17673466415141";
QByteArray data;
data.append("--" + bound + "\r\n");
data.append("Content-Disposition: form-data; name=\"access_token\"\r\n\r\n");
data.append(accessToken + "\r\n");
data.append("--" + bound + "\r\n");
data.append("Content-Disposition: form-data; name=\"source\"; filename=\""
+ file.fileName()+"\"\r\n");
data.append("Content-Type: image/" + fileInfo.suffix().toLower() + "\r\n\r\n");
data.append(file.readAll());
data.append("\r\n");
data.append("--" + bound + "\r\n");
data.append("Content-Disposition: form-data; name=\"message\"\r\n\r\n");
data.append(comment);
data.append("--" + bound + "\r\n");
QNetworkRequest request(uploadUrl);
request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
request.setRawHeader("Accept-Encoding", "gzip,deflate");
request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
request.setRawHeader("Keep-Alive", "300");
request.setRawHeader("Content-Type",
QString("multipart/form-data; boundary=" + bound).toLatin1());
request.setRawHeader("Content-Length", QString(data.size()).toLatin1());
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
QNetworkReply * reply = manager->post(request, data);
QEventLoop wait;
connect(manager, SIGNAL(finished(QNetworkReply*)), &wait, SLOT(quit()));
connect(manager, SIGNAL(finished(QNetworkReply*)), manager, SLOT(deleteLater()));
QTimer::singleShot(10000, &wait, SLOT(quit()));
wait.exec();
QByteArray answer = reply->readAll();
reply->deleteLater();
qDebug() << answer;
2
QString uploadUrl = "https://graph.facebook.com/me/photos?access_token=" +
accessToken;
QString photoPath = QCoreApplication::applicationDirPath() + "/image_example.png";
QFileInfo fileInfo(photoPath);
QFile file(photoPath);
QPixmap pixmap;
pixmap.load(photoPath);
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::ReadWrite);
pixmap.save(&buffer, "png");
buffer.close();
QHttpMultiPart * multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"source\"; filename=\""+ file.fileName()));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"message\""));
imagePart.setBody(data);
multiPart->append(imagePart);
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
QNetworkReply * reply = manager->post(request, multiPart);
QEventLoop wait;
connect(manager, SIGNAL(finished(QNetworkReply*)), &wait, SLOT(quit()));
connect(manager, SIGNAL(finished(QNetworkReply*)), manager, SLOT(deleteLater()));
QTimer::singleShot(10000, &wait, SLOT(quit()));
wait.exec();
QByteArray answer = reply->readAll();
reply->deleteLater();
qDebug() << answer;

I am actually using something similar to your second example. But you need to:
1/ set the size of your image in the imagePart header
2/ you are re-defining ContentDisposition. You need only the first one.
So to recap:
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(type.name()));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"source\"; filename=\""+ file.fileName()));
imagePart.setHeader(QNetworkRequest::ContentLengthHeader, QString::number(fileInfo.size()).toLocal8Bit());
imagePart.setBody(file.readAll());
multiPart->append(imagePart);

Related

Bearer authentication with Qt (QNetworkAccessManager)

I was trying to perform Bearer authentication for https://developer.olx.ua/api/doc#tag/Adverts/paths/~1adverts/get from my Qt app. I use QNetworkAccessManager. But I couldn't find any help on this.
I try this code
QNetworkAccessManager *manager = new QNetworkAccessManager;
QEventLoop loop;
QObject::connect(manager, &QNetworkAccessManager::finished, &loop,
&QEventLoop::quit);
const QUrl url("https://www.olx.ua/api/partner/threads");
QNetworkRequest request {url};
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QString temp = "Bearer " + marketplaceAccessToken;
request.setRawHeader("Authorization", temp.toLocal8Bit());
request.setRawHeader("Version", "2.0");
QNetworkReply *reply = manager->get(request);
loop.exec();
QByteArray dataReply = reply->readAll();
qDebug() << dataReply;
The server reply is {"error":{"status":400,"title":"Bad Request","detail":"Invalid owner in token"}}
How can I fix it?

QNetworkReply - Strange error in enum, OperationCanceled instead of Timeout?

My API server is turned off and i run following code.
I dont understand why QNetworkReply::OperationCanceledError error enum is returned instead of QNetworkReply::TimeoutError. What is wrong? Am i doing something wrong or is it Qt bug?
From documentation that error should be if "the operation was canceled via calls to abort() or close() before it was finished."
I see no reason for that.
QByteArray encodedData = data.toUtf8();
QUrl url("http://myapi/jsonrpc");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkAccessManager manager;
manager.setTransferTimeout(500);
QNetworkReply* reply = manager.post(request, encodedData);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if (reply->error() != QNetworkReply::NoError) {
QString errorMsg = QString("HTTP Network request has failed. Code: ") + QVariant::fromValue(reply->error()).toString();
delete reply;
// error
// here i got QNetworkReply::OperationCanceledError
}
QByteArray response = reply->readAll();
//ok

Invalid data while uploading Image with Imgur API

I want to upload a PNG image with the Imgur API. When I converted a test image (png) to Base64, I got an error that it was not a valid file type. Then I took the test image from the Imgur API documentation (R0lGODlhAQABAIAAAAAAAP//yH5BAEAAAAALAAAABAAEAAAIBRAA7), which worked for an upload, converted it to a "real" image via a converter and tested a Base64 conversion with it. However, I get a different Base64 string (R0lGODlhAQABAOKCrAAAAAAAw7/Dv8O/IcO5BAEAAAAALAAAAAABAAEAAAIBRAA7).
Code snippet:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QUrl url("https://api.imgur.com/3/image");
QNetworkRequest request(url);
request.setRawHeader("Authorization", "Client-ID <hereIsTheClientID>");
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QFile image ("C:/Users/pietr/Desktop/image.gif"); // Result from converting example Base64 from Imgur API-Docs - this file can be read by photo viewers
image.open(QIODevice::ReadOnly);
QTextStream in (&image);
QByteArray imageArray = in.readAll().toUtf8().toBase64();
qDebug() << "Image data:" << imageArray;
QUrlQuery params;
params.addQueryItem("image", imageArray);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->post(request, params.query().toUtf8());
But the reply is...
{
"data":
{
"error":
{
"code":1003,
"message":"File type invalid (2)",
"type":"ImgurException",
"exception":[]},"request":"\/3\/image",
"method":"POST"
},
"success":false,
"status":400
}
Am I making a mistake with the Base64 convert? Why do I get a different value out of the same images?
The image is not sent in the query but as form-data. Using an old answer and applied in your case the solution is:
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QVariantMap::const_iterator i_data = data.constBegin();
while (i_data != data.constEnd()) {
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
postpart.setBody(i_data.value().toByteArray());
multipart->append(postpart);
++i_data;
}
QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
while (i_filenames != filenames.constEnd()) {
QFile *file = new QFile(i_filenames.value());
if(!file->open(QIODevice::ReadOnly)){
delete file;
continue;
}
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=\"%1\"; filename=\"%2\"")
.arg(i_filenames.key(), file->fileName()));
postpart.setBodyDevice(file);
multipart->append(postpart);
file->setParent(multipart);
++i_filenames;
}
return multipart;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const QString CLIENT_ID = QLatin1String("{{clientId}}");
const QString API_URL = QLatin1String("https://api.imgur.com");
QNetworkAccessManager manager;
QNetworkRequest request;
QUrl url(API_URL);
url.setPath("/3/upload");
request.setUrl(url);
request.setRawHeader("Authorization", ("Client-ID "+ CLIENT_ID).toUtf8());
QMap<QString, QString> filenames;
filenames["image"] = "C:/Users/pietr/Desktop/image.gif";
QHttpMultiPart *multipart = buildMultpart({}, filenames);
QNetworkReply *reply = manager.post(request, multipart);
multipart->setParent(reply);
QObject::connect(reply, &QNetworkReply::finished, [reply](){
if(reply->error() == QNetworkReply::NoError){
qDebug().noquote() << reply->readAll();
}
else{
qDebug() << reply->error() << reply->errorString();
}
reply->deleteLater();
QCoreApplication::quit();
});
return a.exec();
}
Output:
{"status":200,"success":true,"data":{"id":"iT63Heu","deletehash":"JRIdjdWP7lMhzuG","account_id":null,"account_url":null,"ad_type":null,"ad_url":null,"title":null,"description":null,"name":"","type":"image/gif","width":100,"height":75,"size":6166,"views":0,"section":null,"vote":null,"bandwidth":0,"animated":false,"favorite":false,"in_gallery":false,"in_most_viral":false,"has_sound":false,"is_ad":false,"nsfw":null,"link":"https://i.imgur.com/iT63Heu.gif","tags":[],"datetime":1634600948,"mp4":"","hls":""}}
If you want to use base64 then change to:
// ...
request.setRawHeader("Authorization", ("Client-ID "+ CLIENT_ID).toUtf8());
QVariantMap data;
QFile image("C:/Users/pietr/Desktop/image.gif");
if(image.open(QIODevice::ReadOnly)){
data["image"] = image.readAll().toBase64();
data["type"] = "base64";
image.close();
}
QHttpMultiPart *multipart = buildMultpart(data, {});
QNetworkReply *reply = manager.post(request, multipart);
// ...

QNetworkAccessManager does not emit signal

So I have this code:
QUrl url("http://...");
QNetworkRequest request(url);
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, SIGNAL(finished()), SLOT(onRequestCompleted()));
connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),SLOT(onError(QNetworkReply::NetworkError)));
and I cant get signal to the other fuction
void IpResolver::onRequestCompleted()
{
QString webContent;
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply)
{
if (reply->error() == QNetworkReply::NoError)
{
QString webContent = reply->readAll();
}
}
}
I cant figure out the solution, help please.
I don't know what exactly you want, but:
Why do you use reply pointer instead of some kind onRequestCompleted(QNetworkReply *reply)?
If you do so:
QUrl url("http://...");
QNetworkRequest request(url);
connect(m_networkManager, &QNetworkAccessManager::finished, this, &IpResolver::onRequestCompleted);
m_networkManager->get(request);
And your slot will be, for example:
void IpResolver::onRequestCompleted(QNetworkReply *reply)
{
QString webContent;
if (reply->error() == QNetworkReply::NoError)
webContent = reply->readAll();
}

create a http communication on blackberry 10 cascade

I'm newbie on development blackberry 10 cascades. I need to use httpget to connect on file xml and get dat from it to display it on list.
There is an example can help me to make http communication or a tutoriel?
All the links for http communication like this https://developer.blackberry.com/cascades/documentation/device_platform/networking/tutorial_http_comm.html didn't work I get 404
Use QNetworkAccessManager, QNetworkRequest and QNetworkReply classes to make http connection.
QNetworkAccessManager* netManager = new QNetworkAccessManager();
QUrl myurl(yourURL);
QNetworkRequest req(url);
QNetworkReply* ipReply = netManager->get(req);
connect(ipReply, SIGNAL(finished(QNetworkReply*)), this, SLOT(onReply(QNetworkReply*)));
}
In onReply slot parse your response
if (reply) {
if (reply->error() == QNetworkReply::NoError) {
int available = reply->bytesAvailable();
if (available > 0) {
int bufSize = sizeof(char) * available + sizeof(char);
QByteArray buffer(bufSize, 0);
int read = reply->read(buffer.data(), available);
response = QString(buffer);
}
} else {
response =
QString("Error: ") + reply->errorString()
+ QString(" status:")
+ reply->attribute(
QNetworkRequest::HttpStatusCodeAttribute).toString();
}
reply->deleteLater();
}
Visit this page for more information
use this code...
QNetworkAccessManager* netManager = new QNetworkAccessManager();
QUrl myurl("http://******");
QNetworkRequest req(myurl);
QNetworkReply* ipReply = netManager->get(req);
QEventLoop eventLoop;
QObject::connect(ipReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
std::cout << "finished" << std::endl; //request finished here
requestFinished(ipReply);