Skip to content

Commit f93e536

Browse files
committed
Add a simplified class for fetching HTTP network content
1 parent e8ee7be commit f93e536

9 files changed

+372
-53
lines changed

python/core/core.sip

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
%Include qgsmessageoutput.sip
6666
%Include qgsmimedatautils.sip
6767
%Include qgsnetworkaccessmanager.sip
68+
%Include qgsnetworkcontentfetcher.sip
6869
%Include qgsofflineediting.sip
6970
%Include qgsogcutils.sip
7071
%Include qgsowsconnection.sip
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
\class QgsNetworkContentFetcher
3+
\ingroup core
4+
\brief HTTP network content fetcher. A simple method for fetching remote HTTP content
5+
and converting the content to standard formats. Url redirects are automatically
6+
handled.
7+
\since 2.5
8+
*/
9+
10+
class QgsNetworkContentFetcher : QObject
11+
{
12+
%TypeHeaderCode
13+
#include <qgsnetworkcontentfetcher.h>
14+
%End
15+
16+
public:
17+
QgsNetworkContentFetcher();
18+
19+
virtual ~QgsNetworkContentFetcher();
20+
21+
/**Fetches content from a remote URL and handles redirects. The finished()
22+
* signal will be emitted when content has been fetched.
23+
* @param url URL to fetch
24+
*/
25+
void fetchContent( const QUrl url );
26+
27+
/**Returns a reference to the network reply
28+
* @returns QNetworkReply for fetched URL content
29+
*/
30+
QNetworkReply* reply();
31+
32+
33+
/**Returns the fetched content as a string
34+
* @returns string containing network content
35+
*/
36+
QString contentAsString() const;
37+
38+
signals:
39+
40+
/**Emitted when content has loaded
41+
*/
42+
void finished();
43+
44+
};

src/core/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ SET(QGIS_CORE_SRCS
115115
qgsmessagelog.cpp
116116
qgsnetworkaccessmanager.cpp
117117
qgsnetworkreplyparser.cpp
118+
qgsnetworkcontentfetcher.cpp
118119
qgsobjectcustomproperties.cpp
119120
qgsofflineediting.cpp
120121
qgsogcutils.cpp
@@ -353,6 +354,7 @@ SET(QGIS_CORE_MOC_HDRS
353354
qgsmessageoutput.h
354355
qgsmessagelog.h
355356
qgsnetworkreplyparser.h
357+
qgsnetworkcontentfetcher.h
356358
qgsofflineediting.h
357359
qgscredentials.h
358360
qgspluginlayer.h
@@ -495,6 +497,7 @@ SET(QGIS_CORE_HDRS
495497
qgsmessageoutput.h
496498
qgsmimedatautils.h
497499
qgsnetworkreplyparser.h
500+
qgsnetworkcontentfetcher.h
498501
qgsobjectcustomproperties.h
499502
qgsofflineediting.h
500503
qgsogcutils.h

src/core/composer/qgscomposerhtml.cpp

+21-53
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgsmessagelog.h"
2222
#include "qgsexpression.h"
2323
#include "qgslogger.h"
24+
#include "qgsnetworkcontentfetcher.h"
2425

2526
#include <QCoreApplication>
2627
#include <QPainter>
@@ -108,58 +109,6 @@ void QgsComposerHtml::setEvaluateExpressions( bool evaluateExpressions )
108109
loadHtml();
109110
}
110111

111-
QString QgsComposerHtml::fetchHtml( QUrl url )
112-
{
113-
QUrl nextUrlToFetch = url;
114-
QNetworkReply* reply = 0;
115-
116-
//loop until fetched valid html
117-
while ( 1 )
118-
{
119-
//set contents
120-
QNetworkRequest request( nextUrlToFetch );
121-
reply = QgsNetworkAccessManager::instance()->get( request );
122-
connect( reply, SIGNAL( finished() ), this, SLOT( frameLoaded() ) );
123-
//pause until HTML fetch
124-
mLoaded = false;
125-
while ( !mLoaded )
126-
{
127-
qApp->processEvents();
128-
}
129-
130-
if ( reply->error() != QNetworkReply::NoError )
131-
{
132-
QgsMessageLog::logMessage( tr( "HTML fetch %1 failed with error %2" ).arg( reply->url().toString() ).arg( reply->errorString() ) );
133-
reply->deleteLater();
134-
return QString();
135-
}
136-
137-
QVariant redirect = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
138-
if ( redirect.isNull() )
139-
{
140-
//no error or redirect, got target
141-
break;
142-
}
143-
144-
//redirect, so fetch redirect target
145-
nextUrlToFetch = redirect.toUrl();
146-
reply->deleteLater();
147-
}
148-
149-
QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
150-
if ( !status.isNull() && status.toInt() >= 400 )
151-
{
152-
QgsMessageLog::logMessage( tr( "HTML fetch %1 failed with error %2" ).arg( reply->url().toString() ).arg( status.toString() ) );
153-
reply->deleteLater();
154-
return QString();
155-
}
156-
157-
QByteArray array = reply->readAll();
158-
reply->deleteLater();
159-
mFetchedHtml = QString( array );
160-
return mFetchedHtml;
161-
}
162-
163112
void QgsComposerHtml::loadHtml()
164113
{
165114
if ( !mWebPage )
@@ -195,6 +144,7 @@ void QgsComposerHtml::loadHtml()
195144
{
196145
loadedHtml = mFetchedHtml;
197146
}
147+
198148
break;
199149
}
200150
case QgsComposerHtml::ManualHtml:
@@ -210,7 +160,7 @@ void QgsComposerHtml::loadHtml()
210160

211161
mLoaded = false;
212162
//set html, using the specified url as base if in Url mode
213-
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mLastFetchedUrl ) : QUrl() );
163+
mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );
214164

215165
//set user stylesheet
216166
QWebSettings* settings = mWebPage->settings();
@@ -279,6 +229,24 @@ void QgsComposerHtml::renderCachedImage()
279229
painter.end();
280230
}
281231

232+
QString QgsComposerHtml::fetchHtml( QUrl url )
233+
{
234+
QgsNetworkContentFetcher fetcher;
235+
//pause until HTML fetch
236+
mLoaded = false;
237+
fetcher.fetchContent( url );
238+
connect( &fetcher, SIGNAL( finished() ), this, SLOT( frameLoaded() ) );
239+
240+
while ( !mLoaded )
241+
{
242+
qApp->processEvents();
243+
}
244+
245+
mFetchedHtml = fetcher.contentAsString();
246+
mActualFetchedUrl = fetcher.reply()->url().toString();
247+
return mFetchedHtml;
248+
}
249+
282250
QSizeF QgsComposerHtml::totalSize() const
283251
{
284252
return mSize;

src/core/composer/qgscomposerhtml.h

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class CORE_EXPORT QgsComposerHtml: public QgsComposerMultiFrame
229229
QString mHtml;
230230
QString mFetchedHtml;
231231
QString mLastFetchedUrl;
232+
QString mActualFetchedUrl; //may be different if page was redirected
232233
bool mLoaded;
233234
QSizeF mSize; //total size in mm
234235
double mHtmlUnitsToMM;

src/core/qgsnetworkcontentfetcher.cpp

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/***************************************************************************
2+
qgsnetworkcontentfetcher.cpp
3+
-------------------
4+
begin : July, 2014
5+
copyright : (C) 2014 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
8+
***************************************************************************/
9+
10+
/***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************/
18+
19+
#include "qgsnetworkcontentfetcher.h"
20+
#include "qgsnetworkaccessmanager.h"
21+
#include "qgsmessagelog.h"
22+
#include "qgsapplication.h"
23+
#include <QNetworkReply>
24+
25+
QgsNetworkContentFetcher::QgsNetworkContentFetcher()
26+
: mReply( 0 )
27+
, mContentLoaded( false )
28+
{
29+
30+
}
31+
32+
QgsNetworkContentFetcher::~QgsNetworkContentFetcher()
33+
{
34+
delete mReply;
35+
}
36+
37+
void QgsNetworkContentFetcher::fetchContent( const QUrl url )
38+
{
39+
QUrl nextUrlToFetch = url;
40+
mContentLoaded = false;
41+
42+
//get contents
43+
QNetworkRequest request( nextUrlToFetch );
44+
45+
mReply = QgsNetworkAccessManager::instance()->get( request );
46+
connect( mReply, SIGNAL( finished() ), this, SLOT( contentLoaded() ) );
47+
}
48+
49+
QNetworkReply *QgsNetworkContentFetcher::reply()
50+
{
51+
if ( !mContentLoaded )
52+
{
53+
return 0;
54+
}
55+
56+
return mReply;
57+
}
58+
59+
QString QgsNetworkContentFetcher::contentAsString() const
60+
{
61+
if ( !mContentLoaded || !mReply )
62+
{
63+
return QString();
64+
}
65+
66+
QByteArray array = mReply->readAll();
67+
return QString( array );
68+
}
69+
70+
void QgsNetworkContentFetcher::contentLoaded( bool ok )
71+
{
72+
Q_UNUSED( ok );
73+
74+
if ( mReply->error() != QNetworkReply::NoError )
75+
{
76+
QgsMessageLog::logMessage( tr( "HTTP fetch %1 failed with error %2" ).arg( mReply->url().toString() ).arg( mReply->errorString() ) );
77+
mContentLoaded = true;
78+
emit finished();
79+
return;
80+
}
81+
82+
QVariant redirect = mReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
83+
if ( redirect.isNull() )
84+
{
85+
//no error or redirect, got target
86+
QVariant status = mReply->attribute( QNetworkRequest::HttpStatusCodeAttribute );
87+
if ( !status.isNull() && status.toInt() >= 400 )
88+
{
89+
QgsMessageLog::logMessage( tr( "HTTP fetch %1 failed with error %2" ).arg( mReply->url().toString() ).arg( status.toString() ) );
90+
}
91+
mContentLoaded = true;
92+
emit finished();
93+
return;
94+
}
95+
96+
//redirect, so fetch redirect target
97+
mReply->deleteLater();
98+
fetchContent( redirect.toUrl() );
99+
}
100+
101+
102+
103+

src/core/qgsnetworkcontentfetcher.h

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/***************************************************************************
2+
qgsnetworkcontentfetcher.h
3+
-------------------
4+
begin : July, 2014
5+
copyright : (C) 2014 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
8+
***************************************************************************/
9+
10+
/***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************/
18+
19+
20+
#ifndef QGSNETWORKCONTENTFETCHER_H
21+
#define QGSNETWORKCONTENTFETCHER_H
22+
23+
#include <QNetworkReply>
24+
#include <QUrl>
25+
26+
/**
27+
\class QgsNetworkContentFetcher
28+
\ingroup core
29+
\brief HTTP network content fetcher. A simple method for fetching remote HTTP content
30+
and converting the content to standard formats. Url redirects are automatically
31+
handled.
32+
\since 2.5
33+
*/
34+
35+
class CORE_EXPORT QgsNetworkContentFetcher : public QObject
36+
{
37+
Q_OBJECT
38+
39+
public:
40+
41+
QgsNetworkContentFetcher();
42+
43+
virtual ~QgsNetworkContentFetcher();
44+
45+
/**Fetches content from a remote URL and handles redirects. The finished()
46+
* signal will be emitted when content has been fetched.
47+
* @param url URL to fetch
48+
*/
49+
void fetchContent( const QUrl url );
50+
51+
/**Returns a reference to the network reply
52+
* @returns QNetworkReply for fetched URL content
53+
*/
54+
QNetworkReply* reply();
55+
56+
/**Returns the fetched content as a string
57+
* @returns string containing network content
58+
*/
59+
QString contentAsString() const;
60+
61+
signals:
62+
63+
/**Emitted when content has loaded
64+
*/
65+
void finished();
66+
67+
private:
68+
69+
QNetworkReply* mReply;
70+
71+
bool mContentLoaded;
72+
73+
private slots:
74+
75+
/**Called when fetchUrlContent has finished loading a url. If
76+
* result is a redirect then the redirect is fetched automatically.
77+
*/
78+
void contentLoaded( bool ok = true );
79+
80+
};
81+
82+
#endif

tests/src/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,4 @@ ADD_QGIS_TEST(shapebursttest testqgsshapeburst.cpp )
128128
ADD_QGIS_TEST(invertedpolygontest testqgsinvertedpolygonrenderer.cpp )
129129
ADD_QGIS_TEST(colorschemeregistry testqgscolorschemeregistry.cpp)
130130
ADD_QGIS_TEST(colorscheme testqgscolorscheme.cpp)
131+
ADD_QGIS_TEST(networkcontentfetcher testqgsnetworkcontentfetcher.cpp )

0 commit comments

Comments
 (0)