Anton Levanter
Anton Levanter

Reputation: 68

How to let QML map traffic pass through a proxy, and disable this proxy for the rest of the program?

I've got an app that uses local network to talk to some devices, and an http proxy to fetch anything external. I'd like to use the map plugin in it. Now the map would require an http proxy to download the tiles. If I set global Qt proxy settings using http_proxy variable, or do it manually using QNetworkProxy::setApplicationProxy then the map is loading fine, but the rest of the program breaks. If I disable the proxy then I can talk to my devices, but I can't see the map. I've tried using QQmlNetworkAccessManagerFactory, as described in the example here, and it works fine for an Image type object, as defined in the view.qml, but it doesn't work if I replace the Image with an Item that contains my map.

Item{
    width: 500
    height: 500
    Map {
        Plugin {
            id: mapPlugin
            name: "osm"
        }
        anchors.fill: parent
        plugin: mapPlugin
        center: QtPositioning.coordinate(59.91, 10.75)
        zoomLevel: 14
        visible: true
    }
}

The MyNetworkAccessManagerFactory::create method never gets called, and I get the following error: QGeoTileRequestManager: Failed to fetch tile (17366,9541,15) 5 times, giving up. Last error message was: 'Error transferring http://c.tile.openstreetmap.org/15/17366/9541.png - server replied: Service Unavailable'. What could be the cause of that? And how can I set a QNetworkProxy for a map plugin?

Upvotes: 1

Views: 749

Answers (1)

eyllanesc
eyllanesc

Reputation: 244132

You have to modify the source code of the plugin:

src/plugins/geoservices/osm/qgeocodingmanagerengineosm.cpp
src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp
src/plugins/geoservices/osm/qgeotiledmappingmanagerengineosm.cpp
src/plugins/geoservices/osm/qplacemanagerengineosm.cpp

In each of these files is a QNetworkAccessManager so you must add the following code:

#include <QtNetwork/QNetworkProxy>

// ...
// constructor

    QString proxy = parameters.value(QStringLiteral("proxy")).toString();
    if (!proxy.isEmpty()) {
#ifndef QT_NO_NETWORKPROXY
        if (proxy.toLower() != QStringLiteral("system")) {
            QUrl proxyUrl(proxy);
            if (proxyUrl.isValid()) {
                qDebug() << "Setting proxy to " << proxyUrl.toString();
                m_networkManager->setProxy(
                            QNetworkProxy(QNetworkProxy::HttpProxy,
                                          proxyUrl.host(),
                                          proxyUrl.port(8080),
                                          proxyUrl.userName(),
                                          proxyUrl.password()));
            }
        } else if (QNetworkProxy::applicationProxy().type() == QNetworkProxy::NoProxy) {
            QNetworkProxyFactory::setUseSystemConfiguration(true);
            qDebug() << "Setting system proxy.";
        }
#else
        qDebug() << "No proxy support";
#endif
    } else {
        qDebug() << "No proxy parameter specified.";
    }

I have created a .patch to make the update simple, for it download it from here.

Then you place the ends in the folder src/plugins/geoservices/osm, apply the patch, compile and install with the following:

git clone -b 5.12.1 [email protected]:qt/qtlocation.git
cd qtlocation/src/plugins/geoservices/osm
wget https://raw.githubusercontent.com/eyllanesc/stackoverflow/master/questions/55105933/proxy-osm.patch
git apply proxy-osm.patch
qmake
make
sudo make install

Then after that you can use the proxy using a plugin parameter:

Map {
    Plugin {
        id: mapPlugin
        name: "osm"
        PluginParameter { name: "proxy"; value: "http://179.179.253.147:8080" } // <---
    }
    anchors.fill: parent
    plugin: mapPlugin
    center: QtPositioning.coordinate(59.91, 10.75)
    zoomLevel: 14
    visible: true
}

Upvotes: 1

Related Questions