1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +01:00

Fixed WMS 1.1.x support

Added support for HTTP basic authorization
This commit is contained in:
Martin Tůma 2018-04-01 20:01:25 +02:00
parent 16f2d7ad34
commit e3e8fdbacf
12 changed files with 131 additions and 58 deletions

View File

@ -29,6 +29,13 @@
#define TIMEOUT 30 /* s */ #define TIMEOUT 30 /* s */
Authorization::Authorization(const QString &username, const QString &password)
{
QString concatenated = username + ":" + password;
QByteArray data = concatenated.toLocal8Bit().toBase64();
_header = "Basic " + data;
}
class Downloader::ReplyTimeout : public QObject class Downloader::ReplyTimeout : public QObject
{ {
public: public:
@ -79,7 +86,8 @@ Downloader::Downloader(QObject *parent) : QObject(parent)
SLOT(downloadFinished(QNetworkReply*))); SLOT(downloadFinished(QNetworkReply*)));
} }
bool Downloader::doDownload(const Download &dl, const Redirect *redirect) bool Downloader::doDownload(const Download &dl,
const QByteArray &authorization, const Redirect *redirect)
{ {
QUrl url(dl.url()); QUrl url(dl.url());
@ -95,6 +103,8 @@ bool Downloader::doDownload(const Download &dl, const Redirect *redirect)
request.setAttribute(ATTR_LEVEL, QVariant(redirect->level())); request.setAttribute(ATTR_LEVEL, QVariant(redirect->level()));
} }
request.setRawHeader("User-Agent", USER_AGENT); request.setRawHeader("User-Agent", USER_AGENT);
if (!authorization.isNull())
request.setRawHeader("Authorization", authorization);
QNetworkReply *reply = _manager.get(request); QNetworkReply *reply = _manager.get(request);
if (reply) { if (reply) {
@ -159,7 +169,8 @@ void Downloader::downloadFinished(QNetworkReply *reply)
} else { } else {
Redirect redirect(origin.isEmpty() ? url : origin, level + 1); Redirect redirect(origin.isEmpty() ? url : origin, level + 1);
Download dl(location, filename); Download dl(location, filename);
doDownload(dl, &redirect); doDownload(dl, reply->request().rawHeader("Authorization"),
&redirect);
} }
} else } else
if (!saveToDisk(filename, reply)) if (!saveToDisk(filename, reply))
@ -173,12 +184,13 @@ void Downloader::downloadFinished(QNetworkReply *reply)
emit finished(); emit finished();
} }
bool Downloader::get(const QList<Download> &list) bool Downloader::get(const QList<Download> &list,
const Authorization &authorization)
{ {
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)); finishEmitted |= doDownload(list.at(i), authorization.header());
return finishEmitted; return finishEmitted;
} }

View File

@ -1,4 +1,4 @@
#ifndef DOWNLOADER_H #ifndef DOWNLOADER_H
#define DOWNLOADER_H #define DOWNLOADER_H
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
@ -11,8 +11,8 @@ class QNetworkReply;
class Download class Download
{ {
public: public:
Download(const QUrl &url, const QString &file) Download(const QUrl &url, const QString &file) : _url(url), _file(file) {}
{_url = url; _file = file;}
const QUrl& url() const {return _url;} const QUrl& url() const {return _url;}
const QString& file() const {return _file;} const QString& file() const {return _file;}
@ -21,6 +21,17 @@ private:
QString _file; QString _file;
}; };
class Authorization
{
public:
Authorization() {}
Authorization(const QString &username, const QString &password);
const QByteArray &header() const {return _header;}
private:
QByteArray _header;
};
class Downloader : public QObject class Downloader : public QObject
{ {
@ -29,7 +40,8 @@ class Downloader : public QObject
public: public:
Downloader(QObject *parent = 0); Downloader(QObject *parent = 0);
bool get(const QList<Download> &list); bool get(const QList<Download> &list, const Authorization &authorization
= Authorization());
void clearErrors() {_errorDownloads.clear();} void clearErrors() {_errorDownloads.clear();}
signals: signals:
@ -42,7 +54,8 @@ private:
class Redirect; class Redirect;
class ReplyTimeout; class ReplyTimeout;
bool doDownload(const Download &dl, const Redirect *redirect = 0); bool doDownload(const Download &dl, const QByteArray &authorization,
const Redirect *redirect = 0);
bool saveToDisk(const QString &filename, QIODevice *data); bool saveToDisk(const QString &filename, QIODevice *data);
QNetworkAccessManager _manager; QNetworkAccessManager _manager;

View File

@ -144,6 +144,12 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
config.yx = (reader.attributes().value("axis") == "yx") config.yx = (reader.attributes().value("axis") == "yx")
? true : false; ? true : false;
config.crs = reader.readElementText(); config.crs = reader.readElementText();
} else if (reader.name() == "authorization") {
QXmlStreamAttributes attr = reader.attributes();
config.authorization = Authorization(
attr.value("username").toString(),
attr.value("password").toString());
reader.skipCurrentElement();
} else } else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
@ -213,10 +219,11 @@ Map *MapSource::loadFile(const QString &path)
if (config.type == WMTS) if (config.type == WMTS)
m = new WMTSMap(config.name, WMTS::Setup(config.url, config.layer, m = new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
config.set, config.style, config.format, config.rest, config.yx, config.set, config.style, config.format, config.rest, config.yx,
config.dimensions)); config.dimensions, config.authorization));
else if (config.type == WMS) else if (config.type == WMS)
m = new WMSMap(config.name, WMS::Setup(config.url, config.layer, m = new WMSMap(config.name, WMS::Setup(config.url, config.layer,
config.style, config.format, config.crs, config.yx)); config.style, config.format, config.crs, config.yx,
config.authorization));
else else
m = new OnlineMap(config.name, config.url, config.zooms, config.bounds); m = new OnlineMap(config.name, config.url, config.zooms, config.bounds);

View File

@ -4,6 +4,7 @@
#include <QList> #include <QList>
#include "common/range.h" #include "common/range.h"
#include "common/rectc.h" #include "common/rectc.h"
#include "downloader.h"
class Map; class Map;
class QXmlStreamReader; class QXmlStreamReader;
@ -35,6 +36,7 @@ private:
bool rest; bool rest;
bool yx; bool yx;
QList<QPair<QString, QString> > dimensions; QList<QPair<QString, QString> > dimensions;
Authorization authorization;
Config(); Config();
}; };

View File

@ -33,7 +33,7 @@ void TileLoader::loadTilesAsync(QList<Tile> &list)
} }
if (!dl.empty()) if (!dl.empty())
_downloader->get(dl); _downloader->get(dl, _authorization);
} }
void TileLoader::loadTilesSync(QList<Tile> &list) void TileLoader::loadTilesSync(QList<Tile> &list)
@ -56,7 +56,7 @@ void TileLoader::loadTilesSync(QList<Tile> &list)
QEventLoop wait; QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit())); QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl)) if (_downloader->get(dl, _authorization))
wait.exec(); wait.exec();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {

View File

@ -3,15 +3,15 @@
#include <QString> #include <QString>
#include "tile.h" #include "tile.h"
#include "downloader.h"
class Downloader;
class TileLoader class TileLoader
{ {
public: public:
TileLoader() {} TileLoader() {}
TileLoader(const QString &url, const QString &dir) TileLoader(const QString &url, const QString &dir,
: _url(url), _dir(dir) {} const Authorization &authorization = Authorization())
: _url(url), _dir(dir), _authorization(authorization) {}
void loadTilesAsync(QList<Tile> &list); void loadTilesAsync(QList<Tile> &list);
void loadTilesSync(QList<Tile> &list); void loadTilesSync(QList<Tile> &list);
@ -27,6 +27,7 @@ private:
QString _url; QString _url;
QString _dir; QString _dir;
Authorization _authorization;
static Downloader *_downloader; static Downloader *_downloader;
}; };

View File

@ -43,20 +43,40 @@ QString WMS::style(QXmlStreamReader &reader)
return name; return name;
} }
RectC WMS::geographicBoundingBox(QXmlStreamReader &reader)
{
qreal left, top, right, bottom;
while (reader.readNextStartElement()) {
if (reader.name() == "westBoundLongitude")
left = reader.readElementText().toDouble();
else if (reader.name() == "eastBoundLongitude")
right = reader.readElementText().toDouble();
else if (reader.name() == "northBoundLatitude")
top = reader.readElementText().toDouble();
else if (reader.name() == "southBoundLatitude")
bottom = reader.readElementText().toDouble();
else
reader.skipCurrentElement();
}
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
void WMS::layer(QXmlStreamReader &reader, CTX &ctx, void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
const QList<QString> &pCRSs, const QList<QString> &pStyles) const QList<QString> &pCRSs, const QList<QString> &pStyles,
RangeF &pScaleDenominator, RectC &pBoundingBox)
{ {
QString name; QString name;
QList<QString> CRSs(pCRSs); QList<QString> CRSs(pCRSs);
QList<QString> styles(pStyles); QList<QString> styles(pStyles);
RangeF scaleDenominator(2132.729583849784, 559082264.0287178); RangeF scaleDenominator(pScaleDenominator);
QRectF boundingBox; RectC boundingBox(pBoundingBox);
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Name") if (reader.name() == "Name")
name = reader.readElementText(); name = reader.readElementText();
else if (reader.name() == "CRS") else if (reader.name() == "CRS" || reader.name() == "SRS")
CRSs.append(reader.readElementText()); CRSs.append(reader.readElementText());
else if (reader.name() == "Style") else if (reader.name() == "Style")
styles.append(style(reader)); styles.append(style(reader));
@ -64,18 +84,18 @@ void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
scaleDenominator.setMin(reader.readElementText().toDouble()); scaleDenominator.setMin(reader.readElementText().toDouble());
else if (reader.name() == "MaxScaleDenominator") else if (reader.name() == "MaxScaleDenominator")
scaleDenominator.setMax(reader.readElementText().toDouble()); scaleDenominator.setMax(reader.readElementText().toDouble());
else if (reader.name() == "BoundingBox") { else if (reader.name() == "LatLonBoundingBox") {
QXmlStreamAttributes attr = reader.attributes(); QXmlStreamAttributes attr = reader.attributes();
if (attr.value("CRS") == ctx.setup.crs()) { boundingBox = RectC(Coordinates(
boundingBox = QRectF(QPointF(
attr.value("minx").toString().toDouble(), attr.value("minx").toString().toDouble(),
attr.value("maxy").toString().toDouble()), attr.value("maxy").toString().toDouble()),
QPointF(attr.value("maxx").toString().toDouble(), Coordinates(attr.value("maxx").toString().toDouble(),
attr.value("miny").toString().toDouble())); attr.value("miny").toString().toDouble()));
}
reader.skipCurrentElement(); reader.skipCurrentElement();
} else if (reader.name() == "Layer") } else if (reader.name() == "EX_GeographicBoundingBox")
layer(reader, ctx, CRSs, styles); boundingBox = geographicBoundingBox(reader);
else if (reader.name() == "Layer")
layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
else else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
@ -93,10 +113,12 @@ void WMS::capability(QXmlStreamReader &reader, CTX &ctx)
{ {
QList<QString> CRSs; QList<QString> CRSs;
QList<QString> styles; QList<QString> styles;
RangeF scaleDenominator(2132.729583849784, 559082264.0287178);
RectC boundingBox;
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Layer") if (reader.name() == "Layer")
layer(reader, ctx, CRSs, styles); layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
else if (reader.name() == "Request") else if (reader.name() == "Request")
request(reader, ctx); request(reader, ctx);
else else
@ -129,10 +151,11 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
reader.setDevice(&file); reader.setDevice(&file);
if (reader.readNextStartElement()) { if (reader.readNextStartElement()) {
if (reader.name() == "WMS_Capabilities") if (reader.name() == "WMS_Capabilities"
|| reader.name() == "WMT_MS_Capabilities")
capabilities(reader, ctx); capabilities(reader, ctx);
else else
reader.raiseError("Not a WMS_Capabilities XML file"); reader.raiseError("Not a WMS Capabilities XML file");
} }
if (reader.error()) { if (reader.error()) {
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber()) _errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
@ -176,7 +199,8 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
return true; return true;
} }
bool WMS::getCapabilities(const QString &url, const QString &file) bool WMS::getCapabilities(const QString &url, const QString &file,
const Authorization &authorization)
{ {
QList<Download> dl; QList<Download> dl;
@ -184,7 +208,7 @@ bool WMS::getCapabilities(const QString &url, const QString &file)
QEventLoop wait; QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit())); QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl)) if (_downloader->get(dl, authorization))
wait.exec(); wait.exec();
if (QFileInfo(file).exists()) if (QFileInfo(file).exists())
@ -201,7 +225,7 @@ WMS::WMS(const QString &file, const WMS::Setup &setup) : _valid(false)
.arg(setup.url()); .arg(setup.url());
if (!QFileInfo(file).exists()) if (!QFileInfo(file).exists())
if (!getCapabilities(capaUrl, file)) if (!getCapabilities(capaUrl, file, setup.authorization()))
return; return;
if (!parseCapabilities(file, setup)) if (!parseCapabilities(file, setup))
return; return;

View File

@ -4,10 +4,11 @@
#include <QString> #include <QString>
#include <QRectF> #include <QRectF>
#include "common/range.h" #include "common/range.h"
#include "common/rectc.h"
#include "projection.h" #include "projection.h"
#include "downloader.h"
class QXmlStreamReader; class QXmlStreamReader;
class Downloader;
class WMS class WMS
{ {
@ -16,11 +17,13 @@ public:
{ {
public: 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, bool yx) const QString &format, const QString &crs, bool yx,
const Authorization &authorization = Authorization())
: _url(url), _layer(layer), _style(style), _format(format), _crs(crs), : _url(url), _layer(layer), _style(style), _format(format), _crs(crs),
_yx(yx) {} _yx(yx), _authorization(authorization) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;}
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;}
@ -34,6 +37,7 @@ public:
QString _format; QString _format;
QString _crs; QString _crs;
bool _yx; bool _yx;
Authorization _authorization;
}; };
@ -41,7 +45,7 @@ public:
const Projection &projection() const {return _projection;} const Projection &projection() const {return _projection;}
const RangeF &scaleDenominator() const {return _scaleDenominator;} const RangeF &scaleDenominator() const {return _scaleDenominator;}
const QRectF &boundingBox() const {return _boundingBox;} const RectC &boundingBox() const {return _boundingBox;}
const QString &version() const {return _version;} const QString &version() const {return _version;}
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
@ -54,7 +58,7 @@ private:
struct CTX { struct CTX {
const Setup &setup; const Setup &setup;
RangeF scaleDenominator; RangeF scaleDenominator;
QRectF boundingBox; RectC boundingBox;
bool layer; bool layer;
bool style; bool style;
bool format; bool format;
@ -64,19 +68,22 @@ private:
format(false), crs(false) {} format(false), crs(false) {}
}; };
RectC geographicBoundingBox(QXmlStreamReader &reader);
QString style(QXmlStreamReader &reader); QString style(QXmlStreamReader &reader);
void getMap(QXmlStreamReader &reader, CTX &ctx); void getMap(QXmlStreamReader &reader, CTX &ctx);
void request(QXmlStreamReader &reader, CTX &ctx); void request(QXmlStreamReader &reader, CTX &ctx);
void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs, void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs,
const QList<QString> &pStyles); const QList<QString> &pStyles, RangeF &pScaleDenominator,
RectC &pBoundingBox);
void capability(QXmlStreamReader &reader, CTX &ctx); void capability(QXmlStreamReader &reader, CTX &ctx);
void capabilities(QXmlStreamReader &reader, CTX &ctx); void capabilities(QXmlStreamReader &reader, CTX &ctx);
bool parseCapabilities(const QString &path, const Setup &setup); bool parseCapabilities(const QString &path, const Setup &setup);
bool getCapabilities(const QString &url, const QString &file); bool getCapabilities(const QString &url, const QString &file,
const Authorization &authorization);
Projection _projection; Projection _projection;
RangeF _scaleDenominator; RangeF _scaleDenominator;
QRectF _boundingBox; RectC _boundingBox;
QString _version; QString _version;
bool _valid; bool _valid;

View File

@ -80,10 +80,10 @@ bool WMSMap::loadWMS()
_yx = (_setup.yx() && wms.version() >= "1.3.0") ? true : false; _yx = (_setup.yx() && wms.version() >= "1.3.0") ? true : false;
_projection = wms.projection(); _projection = wms.projection();
_boundingBox = _yx ? QRectF(QPointF(wms.boundingBox().bottom(), _boundingBox = QRectF(_projection.ll2xy(wms.boundingBox().topLeft()),
wms.boundingBox().right()), QPointF(wms.boundingBox().top(), _projection.ll2xy(wms.boundingBox().bottomRight()));
wms.boundingBox().left())) : wms.boundingBox(); _tileLoader = TileLoader(tileUrl(wms.version()), tilesDir(),
_tileLoader = TileLoader(tileUrl(wms.version()), tilesDir()); _setup.authorization());
computeZooms(wms.scaleDenominator()); computeZooms(wms.scaleDenominator());
updateTransform(); updateTransform();

View File

@ -282,7 +282,8 @@ bool WMTS::parseCapabilities(const QString &path, const Setup &setup)
return true; return true;
} }
bool WMTS::getCapabilities(const QString &url, const QString &file) bool WMTS::getCapabilities(const QString &url, const QString &file,
const Authorization &authorization)
{ {
QList<Download> dl; QList<Download> dl;
@ -290,7 +291,7 @@ bool WMTS::getCapabilities(const QString &url, const QString &file)
QEventLoop wait; QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit())); QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl)) if (_downloader->get(dl, authorization))
wait.exec(); wait.exec();
if (QFileInfo(file).exists()) if (QFileInfo(file).exists())
@ -308,7 +309,7 @@ WMTS::WMTS(const QString &file, const WMTS::Setup &setup) : _valid(false)
.arg(setup.url()); .arg(setup.url());
if (!QFileInfo(file).exists()) if (!QFileInfo(file).exists())
if (!getCapabilities(capaUrl, file)) if (!getCapabilities(capaUrl, file, setup.authorization()))
return; return;
if (!parseCapabilities(file, setup)) if (!parseCapabilities(file, setup))
return; return;

View File

@ -8,8 +8,8 @@
#include <QHash> #include <QHash>
#include "common/rectc.h" #include "common/rectc.h"
#include "projection.h" #include "projection.h"
#include "downloader.h"
class Downloader;
class QXmlStreamReader; class QXmlStreamReader;
class WMTS class WMTS
@ -20,11 +20,14 @@ public:
public: public:
Setup(const QString &url, const QString &layer, const QString &set, Setup(const QString &url, const QString &layer, const QString &set,
const QString &style, const QString &format, bool rest, bool yx, const QString &style, const QString &format, bool rest, bool yx,
const QList<QPair<QString, QString> > &dimensions) : const QList<QPair<QString, QString> > &dimensions,
const Authorization &authorization = Authorization()) :
_url(url), _layer(layer), _set(set), _style(style), _format(format), _url(url), _layer(layer), _set(set), _style(style), _format(format),
_rest(rest), _yx(yx), _dimensions(dimensions) {} _rest(rest), _yx(yx), _dimensions(dimensions),
_authorization(authorization) {}
const QString &url() const {return _url;} const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;}
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;}
@ -43,6 +46,7 @@ public:
bool _rest; bool _rest;
bool _yx; bool _yx;
QList<QPair<QString, QString> > _dimensions; QList<QPair<QString, QString> > _dimensions;
Authorization _authorization;
}; };
class Zoom class Zoom
@ -136,7 +140,8 @@ private:
void contents(QXmlStreamReader &reader, CTX &ctx); void contents(QXmlStreamReader &reader, CTX &ctx);
void capabilities(QXmlStreamReader &reader, CTX &ctx); void capabilities(QXmlStreamReader &reader, CTX &ctx);
bool parseCapabilities(const QString &path, const Setup &setup); bool parseCapabilities(const QString &path, const Setup &setup);
bool getCapabilities(const QString &url, const QString &file); bool getCapabilities(const QString &url, const QString &file,
const Authorization &authorization);
QSet<TileMatrix> _matrixes; QSet<TileMatrix> _matrixes;
QSet<MatrixLimits> _limits; QSet<MatrixLimits> _limits;

View File

@ -23,7 +23,8 @@ bool WMTSMap::loadWMTS()
_bounds = wmts.bounds(); _bounds = wmts.bounds();
_zooms = wmts.zooms(); _zooms = wmts.zooms();
_projection = wmts.projection(); _projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), tilesDir()); _tileLoader = TileLoader(wmts.tileUrl(), tilesDir(),
_setup.authorization());
updateTransform(); updateTransform();