1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +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 */
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
{
public:
@ -79,7 +86,8 @@ Downloader::Downloader(QObject *parent) : QObject(parent)
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());
@ -95,6 +103,8 @@ bool Downloader::doDownload(const Download &dl, const Redirect *redirect)
request.setAttribute(ATTR_LEVEL, QVariant(redirect->level()));
}
request.setRawHeader("User-Agent", USER_AGENT);
if (!authorization.isNull())
request.setRawHeader("Authorization", authorization);
QNetworkReply *reply = _manager.get(request);
if (reply) {
@ -159,7 +169,8 @@ void Downloader::downloadFinished(QNetworkReply *reply)
} else {
Redirect redirect(origin.isEmpty() ? url : origin, level + 1);
Download dl(location, filename);
doDownload(dl, &redirect);
doDownload(dl, reply->request().rawHeader("Authorization"),
&redirect);
}
} else
if (!saveToDisk(filename, reply))
@ -173,12 +184,13 @@ void Downloader::downloadFinished(QNetworkReply *reply)
emit finished();
}
bool Downloader::get(const QList<Download> &list)
bool Downloader::get(const QList<Download> &list,
const Authorization &authorization)
{
bool finishEmitted = false;
for (int i = 0; i < list.count(); i++)
finishEmitted |= doDownload(list.at(i));
finishEmitted |= doDownload(list.at(i), authorization.header());
return finishEmitted;
}

View File

@ -1,4 +1,4 @@
#ifndef DOWNLOADER_H
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkAccessManager>
@ -11,8 +11,8 @@ class QNetworkReply;
class Download
{
public:
Download(const QUrl &url, const QString &file)
{_url = url; _file = file;}
Download(const QUrl &url, const QString &file) : _url(url), _file(file) {}
const QUrl& url() const {return _url;}
const QString& file() const {return _file;}
@ -21,6 +21,17 @@ private:
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
{
@ -29,7 +40,8 @@ class Downloader : public QObject
public:
Downloader(QObject *parent = 0);
bool get(const QList<Download> &list);
bool get(const QList<Download> &list, const Authorization &authorization
= Authorization());
void clearErrors() {_errorDownloads.clear();}
signals:
@ -42,7 +54,8 @@ private:
class Redirect;
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);
QNetworkAccessManager _manager;

View File

@ -144,6 +144,12 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
config.yx = (reader.attributes().value("axis") == "yx")
? true : false;
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
reader.skipCurrentElement();
}
@ -213,10 +219,11 @@ Map *MapSource::loadFile(const QString &path)
if (config.type == WMTS)
m = new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
config.set, config.style, config.format, config.rest, config.yx,
config.dimensions));
config.dimensions, config.authorization));
else if (config.type == WMS)
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
m = new OnlineMap(config.name, config.url, config.zooms, config.bounds);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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