I am developing a Qt/C++ program which encapsulates an HTML5/JQuery web app.
I used to make Ajax requests to read files from a server. But now, I would like Qt to read a file from the local disk and send its content to my web app.
I think I need Qt to catch Ajax requests from the web app and return the file content as the Ajax request result.
The problem is I don't know how to do. For now, I've not found anything about that on google.
Any help is welcome!
I finally found how to do it. I overrode QNetworkAccessManager.
MyQNetworkAccessManager .h:
class MyQNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
protected:
virtual QNetworkReply * createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0);
};
MyQNetworkAccessManager.cpp:
QNetworkReply * MyQNetworkAccessManager::createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData) {
QUrl url = req.url();
QString path = url.path();
if (op == QNetworkAccessManager::GetOperation && path.endsWith("xml")) {
QUrl newUrl;
if(path.endsWith("..")) {
newUrl.setUrl("...");
}
else if(path.endsWith("...")) {
newUrl.setUrl("...");
}
else {
newUrl = url;
}
return QNetworkAccessManager::createRequest(QNetworkAccessManager::GetOperation, QNetworkRequest(newUrl));
}
else
{
return QNetworkAccessManager::createRequest(op, req, outgoingData);
}
}
MainWindow.cpp:
// ....
QWebView *qWebView = new QWebView();
QWebPage *page = qWebView->page();
MyQNetworkAccessManager *networkManager = new MyQNetworkAccessManager();
page->setNetworkAccessManager(networkManager);
qWebView->setPage(page);
qWebView->load(QUrl("..."));
// ....
Related
I'm trying to make an app which sends a image to a server, it transforms the image and it return to the app. But when the app receive the image, only receive a part of it. I did a web with flask and I saw that it send well the picture, and I used Okhttp to download a picture from Internet I don't have any problem.
To send the picture from server I've used:
return flask.send_from_directory('path') and return flask.send_file(...)
To send and receive the picture in the client I've used:
void postRequest(String postUrl, RequestBody postBody) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(postUrl)
.post(postBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Cancel the post on failure.
call.cancel();
Log.d("FAIL", e.getMessage());
// In order to access the TextView inside the UI thread, the code is executed inside runOnUiThread()
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView responseText = findViewById(R.id.responseText);
responseText.setText(R.string.ip_failure);
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
// In order to access the TextView inside the UI thread, the code is executed inside runOnUiThread()
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView responseText = findViewById(R.id.responseText);
responseText.setText("");
try {
Bitmap imagenGAN;
imagenGAN = BitmapFactory.decodeStream(response.body().byteStream());
ImageView imagen = findViewById(R.id.imageView);
imagen.setImageBitmap(imagenGAN);
SaveImage(imagenGAN);
}catch(Exception e){
}
}
});
}
});
}
Example of the received image:
I don't know why I don't receive the full image. Can someone help me?
I'm developing a Qt application and I want to use Google authentication for it. I created a Google API as explained in the following link: https://blog.qt.io/blog/2017/01/25/connecting-qt-application-google-services-using-oauth-2-0/ but I have a problem with it. It doesn't work in many cases and I get ProtocolInvalidOperationError(302) error for https://accounts.google.com/o/oauth2/token request URL in
QOAuthHttpServerReplyHandler::networkReplyFinished(QNetworkReply *reply)
method of Qt class.
Note that I override QOAuthHttpServerReplyHandler::networkReplyFinished(QNetworkReply *reply) to get this error, because it doesn't emit any signal in this case, and the return value for reply->readAll() is as below:
{
"error": "invalid_grant",
"error_description": "Malformed auth code."
}
My Login.cpp code is something as below:
Login::Login() {
google = new QOAuth2AuthorizationCodeFlow;
google->setScope("email");
google->setAuthorizationUrl("https://accounts.google.com/o/oauth2/auth");
google->setClientIdentifier(Utility::decrypt(encryptedClientId));
google->setAccessTokenUrl("https://accounts.google.com/o/oauth2/token");
google->setClientIdentifierSharedKey(Utility::decrypt(encryptedClientSecret));
connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
connect(google,&QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived,[=](const QVariantMap data){
QString code(data["code"].toString());
if(!code2.isEmpty())
{
const QUrl redirectUri= "http://localhost:56413/cb";
QJsonObject postdata;
postdata.insert("code",code);
postdata.insert("client_id", Utility::decrypt(encryptedClientId));
postdata.insert("client_secret", Utility::decrypt(encryptedClientSecret));
postdata.insert("redirect_uri", redirectUri.toString());
postdata.insert("grant_type","authorization_code");
QString serviceURL = "oauth2/v4/token";
NetworkManager::GetInstance()->Post(postdata,serviceURL,"https://www.googleapis.com/",[=](int statusCode,int resultnumber, QJsonObject obj){
if (statusCode >= 200 &&
statusCode < 300)
{
// it's ok, do nothing
}
else {
//show error
}
});
}
});
}
void Login::googleLoginButtonPressed() {
int googlePort = 56413;
if(replyHandler == nullptr)
replyHandler = new QOAuthHttpServerReplyHandlerArio(googlePort, this);
google->setReplyHandler(replyHandler);
QObject::connect(replyHandler, &QOAuthHttpServerReplyHandler::tokensReceived, [=](const QVariantMap &map) {
googleToken = map["id_token"].toString();
connect(google, &QOAuth2AuthorizationCodeFlow::granted, [=]() {
auto reply = google->get(QUrl("https://www.googleapis.com/plus/v1/people/me"));
connect_reply = connect(reply, &QNetworkReply::finished, [=]() {
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode >= 200 &&
statusCode < 300)
{
//NOW register or login the user with email
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll().data());
email = jsonResponse.object().value("emails").toArray()[0].toObject().value("value").toString();
reply->deleteLater();
}
else {
//error
}
});
});
});
google->grant();
}
what's the problem?
Thanks for your help.
We have posted a lengthy document describing how to authenticate with Google SSO and Qt and this is one of the problems we discuss. I suspect the reason is that the login code returned by Google is URL-encoded, and Qt does not decode it automatically for you. So before you set your replyHandler, you need to invoke setModifyParametersFunction to decode it, in the middle of the flow.
google->setModifyParametersFunction([](QAbstractOAuth::Stage stage, QVariantMap* parameters) {
// Percent-decode the "code" parameter so Google can match it
if (stage == QAbstractOAuth::Stage::RequestingAccessToken) {
QByteArray code = parameters->value("code").toByteArray();
(*parameters)["code"] = QUrl::fromPercentEncoding(code);
}
});
I am writing a simple qt network application. I try to read the data from the QNetworkReply but it seems that the finished signal never emit. What happens?
QByteArray utils::Login(QString account)
{
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest* request = new QNetworkRequest();
request->setUrl(QUrl(Urls::loginUrl));
request->setRawHeader("Host", "10.136.2.5");
request->setRawHeader("Referer", "http://10.136.2.5/jnuweb/");
request->setRawHeader("Content-Type", "application/json; charset=utf-8");
request->setRawHeader("Connection", "keep-alive");
request->setRawHeader("X-Requested-With", "XMLHttpRequest");
request->setRawHeader("Accept", "*/*");
request->setRawHeader("Accept-Encoding", "deflate");
QJsonObject* requestContent = new QJsonObject();
requestContent->insert("user", QJsonValue(account));
requestContent->insert("password", QJsonValue(Urls::initPassword));
QNetworkReply* reply = manager-> post(*request, QJsonDocument(*requestContent).toJson(QJsonDocument::Compact));
QObject::connect(reply, &QNetworkReply::finished, [=]()
{
QList<QPair<QByteArray, QByteArray>> responses = reply -> rawHeaderPairs();
qDebug() << responses;
});
}
In My Windows Phone 8 App, I create WebClient object and initiate the with UploadStringAsync. and Create webClientLogin.UploadStringCompleted using UploadStringCompletedEventHandler.
WebClient webClientLogin = new WebClient();
webClientLogin.Headers["content-type"] = "application/json";
webClientLogin.UploadStringCompleted += new UploadStringCompletedEventHandler(webClientUploadStringCompleted);
webClientLogin.UploadStringAsync(new Uri(URL + "LogIn"), "POST", stockiestData);
Here stockiestData is Encoded Using Encoding.UTF8
I Get response as well.
private void webClientUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
var logindetails = JsonConvert.DeserializeObject<LogResponse>(e.Result);
}
But I need to get the Header in this above method (webClientUploadStringCompleted).
I send the header like follows HttpContext.Current.Response.AppendHeader("Msg","Checked");
This response created in WebApi
How to get this?
Able to get header values using sender Object in the following method.
private void webClientUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
}
We have to cast this object as WebClient.
Following method shows how to send in WebApi
[HttpPost]
[ActionName("LogIn")]
public dynamic LogIn(List<Student> Student, HttpRequestMessage request)
{
if (Student!= null)
{
HttpContext.Current.Response.AppendHeader("Msg", "Resived");
}
Following code shows you how to get header value from Windows phone 8
private void webClientUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
WebClient web = (WebClient)sender;
WebHeaderCollection myWebHeaderCollection = (WebHeaderCollection)web.ResponseHeaders;
var v = web.ResponseHeaders["Msg"];
}
So far it seems that importing a service reference in VS2012 with "generate task-based operations" is not working. It os greyed out.
A test with a new project for WPF is working fine - I could select either task-based or async operations.
Is there a simple way on wrapping the async call in a task?
Is there a simple way on wrapping the async call in a task?
Example for WebClient.DownloadStringCompleted
public static class WebClientAsyncExtensions
{
public static Task<string> DownloadStringTask(this WebClient client, Uri address)
{
var tcs = new TaskCompletionSource<string>();
DownloadStringCompletedEventHandler handler = null;
handler = (sender, e) =>
{
client.DownloadStringCompleted -= handler;
if (e.Error != null)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(e.Result);
}
};
client.DownloadStringCompleted += handler;
client.DownloadStringAsync(address);
return tcs.Task;
}
}
Usage:
async void DownloadExample()
{
WebClient client = new WebClient();
await client.DownloadStringTask(new Uri("http://http://stackoverflow.com/questions/13266079/"));
}