1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Added support for custom HTTP headers in map tile requests

This commit is contained in:
Martin Tůma 2023-05-13 15:01:35 +02:00
parent ddc7eb7149
commit d0cea97c90
17 changed files with 69 additions and 45 deletions

View File

@ -53,7 +53,7 @@ Authorization::Authorization(const QString &username, const QString &password)
{ {
QString concatenated = username + ":" + password; QString concatenated = username + ":" + password;
QByteArray data = concatenated.toLocal8Bit().toBase64(); QByteArray data = concatenated.toLocal8Bit().toBase64();
_header = "Basic " + data; _header = HTTPHeader("Authorization", "Basic " + data);
} }
NetworkTimeout::NetworkTimeout(int timeout, QNetworkReply *reply) NetworkTimeout::NetworkTimeout(int timeout, QNetworkReply *reply)
@ -83,9 +83,10 @@ QNetworkAccessManager *Downloader::_manager = 0;
int Downloader::_timeout = 30; int Downloader::_timeout = 30;
bool Downloader::_http2 = true; bool Downloader::_http2 = true;
bool Downloader::doDownload(const Download &dl, const Authorization &auth) bool Downloader::doDownload(const Download &dl, const QList<HTTPHeader> &headers)
{ {
const QUrl &url = dl.url(); const QUrl &url = dl.url();
bool userAgent = false;
if (!url.isValid() || !(url.scheme() == QLatin1String("http") if (!url.isValid() || !(url.scheme() == QLatin1String("http")
|| url.scheme() == QLatin1String("https"))) { || url.scheme() == QLatin1String("https"))) {
@ -103,9 +104,15 @@ bool Downloader::doDownload(const Download &dl, const Authorization &auth)
request.setAttribute(ATTR_REDIRECT_POLICY, request.setAttribute(ATTR_REDIRECT_POLICY,
QNetworkRequest::NoLessSafeRedirectPolicy); QNetworkRequest::NoLessSafeRedirectPolicy);
request.setAttribute(ATTR_HTTP2_ALLOWED, QVariant(_http2)); request.setAttribute(ATTR_HTTP2_ALLOWED, QVariant(_http2));
request.setRawHeader("User-Agent", USER_AGENT);
if (!auth.isNull()) for (int i = 0; i < headers.size(); i++) {
request.setRawHeader("Authorization", auth.header()); const HTTPHeader &hdr = headers.at(i);
request.setRawHeader(hdr.key(), hdr.value());
if (hdr.key() == "User-Agent")
userAgent = true;
}
if (!userAgent)
request.setRawHeader("User-Agent", USER_AGENT);
QFile *file = new QFile(tmpName(dl.file())); QFile *file = new QFile(tmpName(dl.file()));
if (!file->open(QIODevice::WriteOnly)) { if (!file->open(QIODevice::WriteOnly)) {
@ -183,12 +190,12 @@ void Downloader::downloadFinished(QNetworkReply *reply)
} }
bool Downloader::get(const QList<Download> &list, bool Downloader::get(const QList<Download> &list,
const Authorization &authorization) const QList<HTTPHeader> &headers)
{ {
bool finishEmitted = false; bool finishEmitted = false;
for (int i = 0; i < list.count(); i++) for (int i = 0; i < list.count(); i++)
finishEmitted |= doDownload(list.at(i), authorization); finishEmitted |= doDownload(list.at(i), headers);
return finishEmitted; return finishEmitted;
} }

View File

@ -7,9 +7,12 @@
#include <QUrl> #include <QUrl>
#include <QList> #include <QList>
#include <QHash> #include <QHash>
#include "common/kv.h"
class QFile; class QFile;
typedef KV<QByteArray, QByteArray> HTTPHeader;
class Download class Download
{ {
public: public:
@ -29,11 +32,11 @@ public:
Authorization() {} Authorization() {}
Authorization(const QString &username, const QString &password); Authorization(const QString &username, const QString &password);
bool isNull() const {return _header.isNull();} const HTTPHeader &header() const {return _header;}
const QByteArray &header() const {return _header;} bool isNull() const {return _header.key().isNull();}
private: private:
QByteArray _header; HTTPHeader _header;
}; };
class NetworkTimeout : public QObject class NetworkTimeout : public QObject
@ -60,8 +63,7 @@ class Downloader : public QObject
public: public:
Downloader(QObject *parent = 0) : QObject(parent) {} Downloader(QObject *parent = 0) : QObject(parent) {}
bool get(const QList<Download> &list, const Authorization &authorization bool get(const QList<Download> &list, const QList<HTTPHeader> &headers);
= Authorization());
void clearErrors() {_errorDownloads.clear();} void clearErrors() {_errorDownloads.clear();}
static void setNetworkManager(QNetworkAccessManager *manager) static void setNetworkManager(QNetworkAccessManager *manager)
@ -80,7 +82,7 @@ private:
class ReplyTimeout; class ReplyTimeout;
void insertError(const QUrl &url, QNetworkReply::NetworkError error); void insertError(const QUrl &url, QNetworkReply::NetworkError error);
bool doDownload(const Download &dl, const Authorization &auth); bool doDownload(const Download &dl, const QList<HTTPHeader> &headers);
void downloadFinished(QNetworkReply *reply); void downloadFinished(QNetworkReply *reply);
void readData(QNetworkReply *reply); void readData(QNetworkReply *reply);

View File

@ -4,6 +4,7 @@
template <class KEY, class VALUE> template <class KEY, class VALUE>
class KV { class KV {
public: public:
KV() {}
KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {} KV(const KEY &key, const VALUE &value) : _key(key), _value(value) {}
const KEY &key() const {return _key;} const KEY &key() const {return _key;}

View File

@ -64,7 +64,7 @@ bool DEMLoader::loadTiles(const RectC &rect)
} }
} }
return _downloader->get(dl, _authorization); return _downloader->get(dl, _headers);
} }
bool DEMLoader::checkTiles(const RectC &rect) const bool DEMLoader::checkTiles(const RectC &rect) const
@ -97,3 +97,11 @@ QString DEMLoader::tileFile(const DEM::Tile &tile) const
{ {
return _dir.absoluteFilePath(tile.baseName()); return _dir.absoluteFilePath(tile.baseName());
} }
void DEMLoader::setAuthorization(const Authorization &authorization)
{
QList<HTTPHeader> headers;
if (!authorization.isNull())
headers.append(authorization.header());
_headers = headers;
}

View File

@ -16,8 +16,7 @@ public:
DEMLoader(const QString &dir, QObject *parent = 0); DEMLoader(const QString &dir, QObject *parent = 0);
void setUrl(const QString &url) {_url = url;} void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization) void setAuthorization(const Authorization &authorization);
{_authorization = authorization;}
bool loadTiles(const RectC &rect); bool loadTiles(const RectC &rect);
bool checkTiles(const RectC &rect) const; bool checkTiles(const RectC &rect) const;
@ -34,7 +33,7 @@ private:
Downloader *_downloader; Downloader *_downloader;
QString _url; QString _url;
QDir _dir; QDir _dir;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };
#endif // DEMLOADER_H #endif // DEMLOADER_H

View File

@ -189,14 +189,22 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
else else
config.dimensions.append(KV<QString, QString> config.dimensions.append(KV<QString, QString>
(attr.value("id").toString(), reader.readElementText())); (attr.value("id").toString(), reader.readElementText()));
} else if (reader.name() == QLatin1String("header")) {
QXmlStreamAttributes attr = reader.attributes();
if (!attr.hasAttribute("name"))
reader.raiseError("Missing header name");
else
config.headers.append(HTTPHeader(
attr.value("name").toString().toLatin1(),
reader.readElementText().toLatin1()));
} else if (reader.name() == QLatin1String("crs")) { } else if (reader.name() == QLatin1String("crs")) {
config.coordinateSystem = coordinateSystem(reader); config.coordinateSystem = coordinateSystem(reader);
config.crs = reader.readElementText(); config.crs = reader.readElementText();
} else if (reader.name() == QLatin1String("authorization")) { } else if (reader.name() == QLatin1String("authorization")) {
QXmlStreamAttributes attr = reader.attributes(); QXmlStreamAttributes attr = reader.attributes();
config.authorization = Authorization( Authorization auth(attr.value("username").toString(),
attr.value("username").toString(),
attr.value("password").toString()); attr.value("password").toString());
config.headers.append(auth.header());
reader.skipCurrentElement(); reader.skipCurrentElement();
} else if (reader.name() == QLatin1String("tile")) { } else if (reader.name() == QLatin1String("tile")) {
tile(reader, config); tile(reader, config);
@ -252,24 +260,24 @@ Map *MapSource::create(const QString &path, bool *isDir)
case WMTS: case WMTS:
return new WMTSMap(path, config.name, WMTS::Setup(config.url, return new WMTSMap(path, config.name, WMTS::Setup(config.url,
config.layer, config.set, config.style, config.format, config.rest, config.layer, config.set, config.style, config.format, config.rest,
config.coordinateSystem, config.dimensions, config.authorization), config.coordinateSystem, config.dimensions, config.headers),
config.tileRatio); config.tileRatio);
case WMS: case WMS:
return new WMSMap(path, config.name, WMS::Setup(config.url, return new WMSMap(path, config.name, WMS::Setup(config.url,
config.layer, config.style, config.format, config.crs, config.layer, config.style, config.format, config.crs,
config.coordinateSystem, config.dimensions, config.authorization), config.coordinateSystem, config.dimensions, config.headers),
config.tileSize); config.tileSize);
case TMS: case TMS:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, true, false); config.tileSize, config.scalable, true, false);
case OSM: case OSM:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, false, false); config.tileSize, config.scalable, false, false);
case QuadTiles: case QuadTiles:
return new OnlineMap(path, config.name, config.url, config.zooms, return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.headers,
config.tileSize, config.scalable, false, true); config.tileSize, config.scalable, false, true);
default: default:
return new InvalidMap(path, "Invalid map type"); return new InvalidMap(path, "Invalid map type");

View File

@ -40,7 +40,7 @@ private:
CoordinateSystem coordinateSystem; CoordinateSystem coordinateSystem;
bool rest; bool rest;
QList<KV<QString, QString> > dimensions; QList<KV<QString, QString> > dimensions;
Authorization authorization; QList<HTTPHeader> headers;
qreal tileRatio; qreal tileRatio;
int tileSize; int tileSize;
bool scalable; bool scalable;

View File

@ -10,7 +10,7 @@
OnlineMap::OnlineMap(const QString &fileName, const QString &name, OnlineMap::OnlineMap(const QString &fileName, const QString &name,
const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio, const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable, bool invertY, const QList<HTTPHeader> &headers, int tileSize, bool scalable, bool invertY,
bool quadTiles, QObject *parent) bool quadTiles, QObject *parent)
: Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds), : Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds),
_zoom(_zooms.max()), _tileSize(tileSize), _mapRatio(1.0), _zoom(_zooms.max()), _tileSize(tileSize), _mapRatio(1.0),
@ -19,7 +19,7 @@ OnlineMap::OnlineMap(const QString &fileName, const QString &name,
_tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name), _tileLoader = new TileLoader(QDir(ProgramPaths::tilesDir()).filePath(_name),
this); this);
_tileLoader->setUrl(url); _tileLoader->setUrl(url);
_tileLoader->setAuthorization(authorization); _tileLoader->setHeaders(headers);
_tileLoader->setQuadTiles(quadTiles); _tileLoader->setQuadTiles(quadTiles);
connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &OnlineMap::tilesLoaded);
} }

View File

@ -13,7 +13,7 @@ class OnlineMap : public Map
public: public:
OnlineMap(const QString &fileName, const QString &name, const QString &url, OnlineMap(const QString &fileName, const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, qreal tileRatio, const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable, const QList<HTTPHeader> &headers, int tileSize, bool scalable,
bool invertY, bool quadTiles, QObject *parent = 0); bool invertY, bool quadTiles, QObject *parent = 0);
QString name() const {return _name;} QString name() const {return _name;}

View File

@ -88,7 +88,7 @@ void TileLoader::loadTilesAsync(QVector<FetchTile> &list)
} }
if (!dl.empty()) if (!dl.empty())
_downloader->get(dl, _authorization); _downloader->get(dl, _headers);
QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load); QFuture<void> future = QtConcurrent::map(imgs, &TileImage::load);
future.waitForFinished(); future.waitForFinished();
@ -130,7 +130,7 @@ void TileLoader::loadTilesSync(QVector<FetchTile> &list)
if (!dl.empty()) { if (!dl.empty()) {
QEventLoop wait; QEventLoop wait;
connect(_downloader, &Downloader::finished, &wait, &QEventLoop::quit); connect(_downloader, &Downloader::finished, &wait, &QEventLoop::quit);
if (_downloader->get(dl, _authorization)) if (_downloader->get(dl, _headers))
wait.exec(); wait.exec();
for (int i = 0; i < tl.size(); i++) { for (int i = 0; i < tl.size(); i++) {

View File

@ -14,8 +14,7 @@ public:
TileLoader(const QString &dir, QObject *parent = 0); TileLoader(const QString &dir, QObject *parent = 0);
void setUrl(const QString &url) {_url = url;} void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization) void setHeaders(const QList<HTTPHeader> &headers) {_headers = headers;}
{_authorization = authorization;}
void setScaledSize(int size); void setScaledSize(int size);
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;} void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
@ -33,7 +32,7 @@ private:
Downloader *_downloader; Downloader *_downloader;
QString _url; QString _url;
QString _dir; QString _dir;
Authorization _authorization; QList<HTTPHeader> _headers;
int _scaledSize; int _scaledSize;
bool _quadTiles; bool _quadTiles;
}; };

View File

@ -345,7 +345,7 @@ WMS::WMS(const QString &file, const WMS::Setup &setup, QObject *parent)
QList<Download> dl; QList<Download> dl;
dl.append(Download(url, _path)); dl.append(Download(url, _path));
_valid = downloader->get(dl, _setup.authorization()); _valid = downloader->get(dl, _setup.headers());
} else { } else {
_ready = true; _ready = true;
_valid = parseCapabilities(); _valid = parseCapabilities();

View File

@ -23,13 +23,13 @@ public:
Setup(const QString &url, const QString &layer, const QString &style, Setup(const QString &url, const QString &layer, const QString &style,
const QString &format, const QString &crs, const CoordinateSystem &cs, const QString &format, const QString &crs, const CoordinateSystem &cs,
const QList<KV<QString, QString> > &dimensions, const QList<KV<QString, QString> > &dimensions,
const Authorization &authorization = Authorization()) const QList<HTTPHeader> &headers)
: _url(url), _layer(layer), _style(style), _format(format), : _url(url), _layer(layer), _style(style), _format(format),
_crs(crs), _cs(cs), _dimensions(dimensions), _crs(crs), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {} _headers(headers) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;} const QList<HTTPHeader> &headers() const {return _headers;}
const QString &layer() const {return _layer;} const QString &layer() const {return _layer;}
const QString &style() const {return _style;} const QString &style() const {return _style;}
const QString &format() const {return _format;} const QString &format() const {return _format;}
@ -46,7 +46,7 @@ public:
QString _crs; QString _crs;
CoordinateSystem _cs; CoordinateSystem _cs;
QList<KV<QString, QString> > _dimensions; QList<KV<QString, QString> > _dimensions;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };

View File

@ -74,7 +74,7 @@ WMSMap::WMSMap(const QString &fileName, const QString &name,
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
_tileLoader = new TileLoader(tilesDir, this); _tileLoader = new TileLoader(tilesDir, this);
_tileLoader->setAuthorization(setup.authorization()); _tileLoader->setHeaders(setup.headers());
connect(_tileLoader, &TileLoader::finished, this, &WMSMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &WMSMap::tilesLoaded);
_wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); _wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);

View File

@ -361,7 +361,7 @@ WMTS::WMTS(const QString &file, const WMTS::Setup &setup, QObject *parent)
QList<Download> dl; QList<Download> dl;
dl.append(Download(url.toString(), _path)); dl.append(Download(url.toString(), _path));
_valid = downloader->get(dl, _setup.authorization()); _valid = downloader->get(dl, _setup.headers());
} else { } else {
_ready = true; _ready = true;
_valid = init(); _valid = init();

View File

@ -27,13 +27,13 @@ public:
const QString &style, const QString &format, bool rest, const QString &style, const QString &format, bool rest,
const CoordinateSystem &cs, const CoordinateSystem &cs,
const QList<KV<QString, QString> > &dimensions, const QList<KV<QString, QString> > &dimensions,
const Authorization &authorization = Authorization()) const QList<HTTPHeader> &headers)
: _url(url), _layer(layer), _set(set), _style(style), : _url(url), _layer(layer), _set(set), _style(style),
_format(format), _rest(rest), _cs(cs), _dimensions(dimensions), _format(format), _rest(rest), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {} _headers(headers) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;} const QList<HTTPHeader> &headers() const {return _headers;}
const QString &layer() const {return _layer;} const QString &layer() const {return _layer;}
const QString &set() const {return _set;} const QString &set() const {return _set;}
const QString &style() const {return _style;} const QString &style() const {return _style;}
@ -52,7 +52,7 @@ public:
bool _rest; bool _rest;
CoordinateSystem _cs; CoordinateSystem _cs;
QList<KV<QString, QString> > _dimensions; QList<KV<QString, QString> > _dimensions;
Authorization _authorization; QList<HTTPHeader> _headers;
}; };
class Zoom class Zoom

View File

@ -20,7 +20,7 @@ WMTSMap::WMTSMap(const QString &fileName, const QString &name,
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name)); QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
_tileLoader = new TileLoader(tilesDir, this); _tileLoader = new TileLoader(tilesDir, this);
_tileLoader->setAuthorization(setup.authorization()); _tileLoader->setHeaders(setup.headers());
connect(_tileLoader, &TileLoader::finished, this, &WMTSMap::tilesLoaded); connect(_tileLoader, &TileLoader::finished, this, &WMTSMap::tilesLoaded);
_wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this); _wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);