My application consists from two apps. And one of them may ask another to perform some commands through a REST call (call an URL on localhost). For this purposes we use QNetworkAccessManager (for put, get and post request).
Now there is a problem - device may go offline sometimes and when he does it - for some reason we can't use rest calls through access manager. It seems that it happen when network configuration that it uses is destroyed (like disabling Wifi adapter etc). When this configuration is restored (enabled Wifi), access manager starts work again.
Another detail - when we start app while we are offline - it works regardless of online state. It may be related to this.
This reproduces on both Win and Mac.
So the question is how can i reliably use QNetworkAccessManager for this purposes irregardless of devices online state? We use this manager only for localhost REST calls. What default network configuration or behavior should i set?
Example of usage below:
mNetManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setRawHeader("User-Agent", "AppName/1.0");
request.setUrl(QUrl(url));
*reply = mNetManager->get(request);
Edit: online state is not required, since i need this access manager only for accessing local URLs on browser
It appears you can force network accessibility to get local content:
mNetManager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setRawHeader("User-Agent", "AppName/1.0");
request.setUrl(QUrl(url));
mNetManager->setNetworkAccessible(QNetworkAccessManager::Accessible); // <--
auto reply = mNetManager->get(request);
The QNetworkAccessManager have stuff for network availability. Why not using it?
QNetworkAccessManager * mNetManager = new QNetworkAccessManager(this);
connect(mNetManager, &QNetworkAccessManager::networkAccessibleChanged,
this, &YourClass::slotExecutedWhenNetworkAccessibilityChanges);
NetworkAccessibility netAcc = mNetManager->networkAccessible();
switch (netAcc) {
case QNetworkAccessManager::Accessible:
// You are online.
break;
case QNetworkAccessManager::NotAccessible:
// You are offline.
break;
case QNetworkAccessManager::UnknownAccessibility:
default:
// You know nothing, Jon Snow.
break;
}
Related
I get a strange issue with my Qt-based software. The software uses QNetworkAccessManager to get and post information to a webserver using SSL encryption and the user have the option to use a proxy if needed. We do still have some limited information sent without SSL (to an http address, no added "s"), we use our own encryption for that part. Just haven't updated that part yet and that's not causing any issues right now (which actually is partially why this issue is strange).
You see, when I try to Post data using both a proxy and SSL I get error 103: "the remote host name was not found (invalid hostname)", but posting the data SSL and no proxy works fine, as does posting the data with proxy and no SSL. The exact same data can however be sent with both proxy and SSL using Postman, so there doesn't seem to be any issue with the data. Get works to get all data regardless of SSL and proxy.
Have anyone else had a similar issue or have an idea of what might be the cause? If so, have you found any solutions or workarounds?
Here's the proxy setup for the Get part:
nam = new QNetworkAccessManager(this);
connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(namFinished(QNetworkReply*)));
if(portalCommSettingsVO.isUseProxy()){
QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, portalCommSettingsVO.getProxyUrl(), static_cast<quint16>(portalCommSettingsVO.getProxyPort()));
if(!portalCommSettingsVO.getProxyUser().operator ==("")){
proxy.setUser(portalCommSettingsVO.getProxyUser());
proxy.setPassword(portalCommSettingsVO.getProxyPassword());
}
nam->setProxy(proxy);
}else{
nam->setProxy(QNetworkProxy::NoProxy);
}
And here's where I connect and Get the data:
QString routingUrlString = Utils::getUrlRoutingServer();
routingUrlString.append(QString::number(Id));
QUrl routingUrl(routingUrlString);
QNetworkRequest routingRequest;
routingRequest.setSslConfiguration(QSslConfiguration::defaultConfiguration());
routingRequest.setUrl(routingUrl);
reply = nam->get(routingRequest);
connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(downloadError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(const QList<QSslError>)), this,SLOT(downloadSSLError(const QList<QSslError>)));
connect(reply,SIGNAL(finished()),this,SLOT(routingDownloadFinished()));
Compared to the proxy setup for the Post part:
nam = new QNetworkAccessManager(this);
connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(namFinished(QNetworkReply*)));
if(portalCommSettingsVO.isUseProxy()){
QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy, portalCommSettingsVO.getProxyUrl(), static_cast<quint16>(portalCommSettingsVO.getProxyPort()));
if(!portalCommSettingsVO.getProxyUser().operator ==("")){
proxy.setUser(portalCommSettingsVO.getProxyUser());
proxy.setPassword(portalCommSettingsVO.getProxyPassword());
}
nam->setProxy(proxy);
}else{
nam->setProxy(QNetworkProxy::NoProxy);
}
And where I connect and try to post the data:
QUrl url(currentObject.getUploadUrl());
QUrlQuery query;
query.addQueryItem("mode", "save");
url.setQuery(query.query());
QNetworkRequest request;
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
request.setUrl(QUrl(url));
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/x-www-form-urlencoded"));
reply = nam->post(request,arr);
connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(uploadError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(const QList<QSslError>)), this,SLOT(uploadSSLError(const QList<QSslError>)));
connect(reply,SIGNAL(finished()),this,SLOT(uploadFinished()));
Pretty similar right? I can't understand why the Post wont work!
PS. the "arr"-variable is an array of data in base64. The same data could be sent through Postman without difficulty so I doubt that's where the issue is.
I want to enter in the program, ip, username and password of a virtual server(vps), and the program checks that the username and password are correct or not.
I used the following code
void MainWindow::test()
{
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QUrl url;
url.setHost("xx.xxx.xx.xx");
url.setPort(3389);
url.setUserName("administrator");
url.setPassword("xxxx");
manager->get(QNetworkRequest(url));
connect(manager,&QNetworkAccessManager::finished, this, &MainWindow::connFinished);
}
output:
QNetworkReply::NetworkError(ProtocolUnknownError)
please guide me
If you only want to know, if the host is online:
I would suggest you use connectToHost from QAbstractSocket Class. The RDP-Protocol is based on TCP/UDP according to Wikipedia and listens on 3389 (what you said in the comments.).
If the connection on TCP 3389 is successful, the host is online.
If you want to verify if the host is online and the authentication works you have to implement your own RDP-library such as FreeRDP, because Qt does not provide any core modules for RDP.
I'm using QT 5.0.2 prebuilt and QT creator 2.7.0 and my goal is to login to steam network programmatically using uname, password and steamguard code. Or to be more precise: get QNetworkAccessManager from its initial uninitialized state to the state where it could retrieve any data from steam related sites as if it was logged in as some user.
So the login happens in 4 steps (4 request-response combos):
NOTE: Steam site javascript uses post in all requests, but it seems that get also works.
Assume username "hyper"
1. Initial request:
post https://store.steampowered.com/login/getrsakey/?username=hyper
Here is my function:
void http::steam_auth(const QString &uname, const QString &pwd)
{
QString encrypted_password, sg, pkey_exp, pkey_mod, timestamp, emailsteamid;
QJsonDocument json_buffer;
QByteArray buffer;
QUrl rsa(steam_getrsa), login(steam_dologin); //steam login urls
QUrlQuery urlquery;
Here we send our request:
urlquery.addQueryItem("username", uname); //first step
urlquery.addQueryItem("l", "english"); //set communication language
rsa.setQuery(urlquery);
QNetworkRequest first(rsa);
QNetworkReply *reply = this->get(first);
buffer = reply->readAll();
As a response we get:
{"success":true,"publickey_mod":"AC41A964789638B6A3B3BD5ADD9F3680FA45881C70FD2032B10A3BB6D2ACF021C2B3D564DC44DE3054E3BF78A1753399223C794A0DED03A76CD1F1DFE851E30F0D6F14484C258EB6053676A47D20A68E11ECCD783F343594DDA3817AA5DCCE75FAF5C68BB197DA1FF12F22F9FCD83624D00A23CC57A367563ADBBCEDF5C8742A57B12A4BD04DC02A55C80F4F6984B1E2D5A99081510326E1C6BAB2C2723560487E8F7EA1A2CB55AEFC5594C9FBB71CAD553CB2D866214BC41156259FEC55362D38DCDBE8FADFB577FE0736CE3E37AF6D2CDDF28FA218C1E477E29B17713BFC48A227455B6B0DE09884CC0820CE40CD4877D93704D00E20A235FCF55D100A01C1","publickey_exp":"010001","timestamp":"284691100000"}
Which means everything is ok.
Now we need to encrypt our password before sending it
json_buffer = QJsonDocument::fromJson(buffer);
pkey_exp = json_buffer.object().value("publickey_exp").toString();
pkey_mod = json_buffer.object().value("publickey_mod").toString();
timestamp = json_buffer.object().value("timestamp").toString();
delete reply;
urlquery.clear();
encrypted_password = app::core::get_encrypted_password(pwd, pkey_exp, pkey_mod);
2. Send encrypted password:
urlquery.addQueryItem("username", uname);
urlquery.addQueryItem("password", encrypted_password);
urlquery.addQueryItem("emailauth", "");
urlquery.addQueryItem("captchagid", "");
urlquery.addQueryItem("captcha_text", "");
urlquery.addQueryItem("emailsteamid", "");
urlquery.addQueryItem("rsatimestamp", timestamp);
urlquery.addQueryItem("remember_login", "false");
login.setQuery(urlquery);
QNetworkRequest second(login);
second.setUrl(login);
reply = this->get(second);
buffer = reply->readAll();
We get a request string as follows:
post https://store.steampowered.com/login/dologin/?username=solidbeetle2&password=YmhTKVkRXyiCYe6wx+ZJ8PIhzj4A4BLWgJFOE5ge7nbIAM6m1G9qHh+Iqx30ZLdB0wW0xdWDNCgHBNPHKLA+P2pYhPF0DeL9v8UQsers6NCNNPZ0SFN4HhNlu6Gwh8QAjrNykev7N5FADXwJnFjPBvmvthATmrktVEtFYF54lckaPnijXYSDIpfEjmG8+bCDKT/GLaUiftA2QauUY9ap8WHSEoykiTmfL344ghzjhCA33UKx0NIgBrDdI1RLfHVcmAcU/c9NEhoHLOT93n8hqWY+YVx9VbOcKqqZPrbCiQoU2BZrqK6N7aj+K6kH0VWHH7+LD2KJx4BUJgHOmNqVDg%3D%3D&emailauth=&captchagid=&captcha_text=&emailsteamid=&rsatimestamp=50693150000&remember_login=false
It is perfectly valid as far as I can tell, JS on steam site sends ajax with the same, but...
Here is the problem
When I get a response with this it says message:Invalid login in json... But if I save the full query string from my request to file and then paste it either in browser or in HTTP Request builder inside HTTP Analyzer, it works fine displaying message:SteamGuard
What could be wrong? Is there something I'm missing? Does QNetworkAccessManager break this somehow?:c
Sorry if something is not clear, I'll try my best to explain again if needed.
Thanks in advance!
P.S. Is there any solid way to examine requests my app is sending?
P.S.S. my qt creator seems to crash when debugging projects with qml option, idk why...
I have inspected all this stuff and finally was able to achieve my goal.
In short the problem was in qt's web-oriented classes. It seemed obvious that qurlquery should encode characters such as / or = in their %-encoded form.. but it is NOT the case, therefore I had to replace them manually in QString. If someone needs a working routine, it can be found here (Its not pretty :c)
I have a flash video player which requests a flv file from a central server. That server might redirect the request to a server from the user's country if possible, a lot like a CDN.
This video player also reports usage stats. One thing I'd like to report is the true server/location from which the player is streaming the video from. So basically, if it gets redirected I want to know about it.
It seems that you can't extract the url from a URLLoader, you can only keep a copy of the URLRequest that you constructed it with.
I notice that you can listen for HTTP status events, which would include a 302 or similar. But unfortunately, the HTTPStatusEvent object doesn't show the redirected location.
Any ideas about how to monitor for a redirect, and get the redirected location?
I'm a bit surprised Flash allows you to redirect a video request at all. I did a bit of digging and it looks like you can get the info:
Handling Crossdomain.xml and 302 Redirects Using NetStream
His post specifically talks about the trouble of security issues that arise because of the fact some operations fail if data is from an untrusted server. Since he doesn't know where his video is coming from (302 redirect) the Flash Player doesn't trust it and prevents some operations on the loaded content.
How he gets the server the content was actually loaded from is to do an operation on the file that should not be allowed and he parses the domain information from the error message:
try
{
var bit:BitmapData = new BitmapData(progressiveVideoPlayer.measuredWidth, progressiveVideoPlayer.measuredHeight, false, 0x000000);
bit.draw(progressiveVideoPlayer);
}
catch(error:SecurityError)
{
var list:Array = error.toString().split(" ");
var swfURL:String = list[7] as String;
var domain:String = list[10] as String;
domain = domain.substring(0, domain.length - 1);
var domainList:Array = domain.split("/");
var protocol:String = domainList[0] as String;
var address:String = domainList[2];
var policyFileURL:String = protocol + "//" + address + "/crossdomain.xml";
Security.loadPolicyFile(policyFileURL);
}
Notice he is doing it so that he can load the policy file (to allow the security restricted operations on the file). I'm not sure it will be helpful to you but at least read the article and have a think about it. You may contact the blog author directly too - he is pretty active in the general Flash community.
hi friends i'm a newbie in blackberry programming and have managed to make a small application... The application downloads an xml file through http and parses it and displays it on the screen... now the problem is that though it works fine on my simulator... the client complains that he's getting an error in connection if he connects it through 3G... do i need to add anything other than the following...
// Build a document based on the XML file.
url = <my clients url file>;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
hc = (HttpConnection)Connector.open(url+";deviceside=true");
hc.setRequestMethod(HttpConnection.GET);
InputStream inputStream = hc.openInputStream();
hc.getFile();
Document document = builder.parse(inputStream);
hc.close();
inputStream.close();
Do i need to add anything to make it download http content through 3G also??
Specifying "deviceside=true" requires the device have the APN correctly configured, or you include APN specification in the URL. Have a look at this video.
You need to be able to detect what sort of connection the device is using as was said above deviceside=true works only for APN. If you want to just test it out try using
;deviceside=false //for mds
;deviceside=false;ConnectionType=mds-public //for bis-b
;interface=wifi //for wifi