27
27
#include < qapplication.h>
28
28
#include < q3url.h>
29
29
30
+ #include < QTimer>
31
+
32
+ static int NETWORK_TIMEOUT_MSEC = (120 * 1000 ); // 120 seconds
30
33
31
34
QgsHttpTransaction::QgsHttpTransaction (QString uri, QString proxyHost, Q_UINT16 proxyPort)
32
35
: httpurl(uri),
33
36
httphost(proxyHost),
34
37
httpport(proxyPort),
35
- httpresponsecontenttype(0 )
38
+ httpresponsecontenttype(0 ),
39
+ mError(0 )
36
40
{
37
41
#ifdef QGISDEBUG
38
42
std::cout << " QgsHttpTransaction: constructing." << std::endl;
@@ -87,40 +91,49 @@ bool QgsHttpTransaction::getSynchronously(QByteArray &respondedContent, int redi
87
91
// Proxy -> send complete URL
88
92
path = httpurl;
89
93
}
90
- http = new Q3Http ( httphost, httpport );
94
+ http = new Q3Http ( httphost, httpport );
95
+ mWatchdogTimer = new QTimer ( this );
91
96
92
97
#ifdef QGISDEBUG
93
98
qWarning (" QgsHttpTransaction::getSynchronously: qurl.host() is '" +qurl.host ()+ " '." );
94
99
qWarning (" QgsHttpTransaction::getSynchronously: qurl.encodedPathAndQuery() is '" +qurl.encodedPathAndQuery ()+" '." );
95
100
std::cout << " path = " << path.ascii () << std::endl;
96
101
#endif
97
-
102
+
98
103
httpresponse.truncate (0 );
99
104
httpid = http->get ( path );
100
- httpactive = TRUE ;
101
-
102
- connect (http, SIGNAL ( requestStarted ( int ) ),
105
+
106
+ connect (http, SIGNAL ( requestStarted ( int ) ),
103
107
this , SLOT ( dataStarted ( int ) ) );
104
-
105
- connect (http, SIGNAL ( responseHeaderReceived ( const Q3HttpResponseHeader& ) ),
108
+
109
+ connect (http, SIGNAL ( responseHeaderReceived ( const Q3HttpResponseHeader& ) ),
106
110
this , SLOT ( dataHeaderReceived ( const Q3HttpResponseHeader& ) ) );
107
-
108
- connect (http, SIGNAL ( readyRead ( const Q3HttpResponseHeader& ) ),
111
+
112
+ connect (http, SIGNAL ( readyRead ( const Q3HttpResponseHeader& ) ),
109
113
this , SLOT ( dataReceived ( const Q3HttpResponseHeader& ) ) );
110
-
111
- connect (http, SIGNAL ( dataReadProgress ( int , int ) ),
114
+
115
+ connect (http, SIGNAL ( dataReadProgress ( int , int ) ),
112
116
this , SLOT ( dataProgress ( int , int ) ) );
113
117
114
- connect (http, SIGNAL ( requestFinished ( int , bool ) ),
118
+ connect (http, SIGNAL ( requestFinished ( int , bool ) ),
115
119
this , SLOT ( dataFinished ( int , bool ) ) );
116
120
117
- connect (http, SIGNAL ( stateChanged ( int ) ),
121
+ connect (http, SIGNAL ( stateChanged ( int ) ),
118
122
this , SLOT ( dataStateChanged ( int ) ) );
119
123
124
+ // Set up the watchdog timer
125
+ connect (mWatchdogTimer , SIGNAL ( timeout () ),
126
+ this , SLOT ( networkTimedOut () ) );
127
+
128
+ mWatchdogTimer ->setSingleShot (TRUE );
129
+ mWatchdogTimer ->start (NETWORK_TIMEOUT_MSEC);
130
+
120
131
#ifdef QGISDEBUG
121
132
std::cout << " QgsHttpTransaction::getSynchronously: Starting get." << std::endl;
122
133
#endif
123
134
135
+ httpactive = TRUE ;
136
+
124
137
// A little trick to make this function blocking
125
138
while ( httpactive )
126
139
{
@@ -132,14 +145,22 @@ bool QgsHttpTransaction::getSynchronously(QByteArray &respondedContent, int redi
132
145
133
146
#ifdef QGISDEBUG
134
147
std::cout << " QgsHttpTransaction::getSynchronously: Response received." << std::endl;
135
-
148
+
136
149
// QString httpresponsestring(httpresponse);
137
150
// std::cout << "QgsHttpTransaction::getSynchronously: Response received; being '" << httpresponsestring << "'." << std::endl;
138
151
#endif
139
-
140
152
141
153
delete http;
142
154
155
+ // Did we get an error? If so, bail early
156
+ if (!mError .isNull ())
157
+ {
158
+ #ifdef QGISDEBUG
159
+ std::cout << " QgsHttpTransaction::getSynchronously: Processing an error '" << mError .toLocal8Bit ().data () << " '." << std::endl;
160
+ #endif
161
+ return FALSE ;
162
+ }
163
+
143
164
// Do one level of redirection
144
165
// TODO make this recursable
145
166
// TODO detect any redirection loops
@@ -195,15 +216,28 @@ void QgsHttpTransaction::dataHeaderReceived( const Q3HttpResponseHeader& resp )
195
216
resp.value (" Content-Type" ).toLocal8Bit ().data () << " '." << std::endl;
196
217
#endif
197
218
219
+ // We saw something come back, therefore restart the watchdog timer
220
+ mWatchdogTimer ->start (NETWORK_TIMEOUT_MSEC);
221
+
198
222
if (resp.statusCode () == 302 ) // Redirect
199
223
{
200
224
// Grab the alternative URL
201
225
// (ref: "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html")
202
226
httpredirecturl = resp.value (" Location" );
203
227
}
228
+ else if (resp.statusCode () == 200 ) // OK
229
+ {
230
+ // NOOP
231
+ }
232
+ else
233
+ {
234
+ mError = QString ( tr (" WMS Server responded unexpectedly with HTTP Status Code %1 (%2)" ) )
235
+ .arg ( resp.statusCode () )
236
+ .arg ( resp.reasonPhrase () );
237
+ }
204
238
205
239
httpresponsecontenttype = resp.value (" Content-Type" );
206
-
240
+
207
241
}
208
242
209
243
@@ -224,7 +258,7 @@ void QgsHttpTransaction::dataReceived( const Q3HttpResponseHeader& resp )
224
258
// std::cout << "QgsHttpTransaction::dataReceived." << std::endl;
225
259
// std::cout << "QgsHttpTransaction::dataReceived: received '" << data << "'."<< std::endl;
226
260
#endif
227
-
261
+
228
262
}
229
263
230
264
@@ -235,6 +269,9 @@ void QgsHttpTransaction::dataProgress( int done, int total )
235
269
// std::cout << "QgsHttpTransaction::dataProgress: got " << done << " of " << total << std::endl;
236
270
#endif
237
271
272
+ // We saw something come back, therefore restart the watchdog timer
273
+ mWatchdogTimer ->start (NETWORK_TIMEOUT_MSEC);
274
+
238
275
QString status;
239
276
240
277
if (total)
@@ -258,11 +295,30 @@ void QgsHttpTransaction::dataFinished( int id, bool error )
258
295
#ifdef QGISDEBUG
259
296
std::cout << " QgsHttpTransaction::dataFinished with ID " << id << " ." << std::endl;
260
297
298
+ // The signal that this slot is connected to, Q3Http::requestFinished,
299
+ // appears to get called at the destruction of the Q3Http if it is
300
+ // still working at the time of the destruction.
301
+ //
302
+ // This situation may occur when we've detected a timeout and
303
+ // we already set httpactive = FALSE.
304
+ //
305
+ // We have to detect this special case so that the last known error string is
306
+ // not overwritten (it should rightfully refer to the timeout event).
307
+ if (!httpactive)
308
+ {
309
+ std::cout << " QgsHttpTransaction::dataFinished - http activity loop already FALSE." << std::endl;
310
+ return ;
311
+ }
312
+
261
313
if (error)
262
314
{
263
315
std::cout << " QgsHttpTransaction::dataFinished - however there was an error." << std::endl;
264
316
std::cout << " QgsHttpTransaction::dataFinished - " << http->errorString ().toLocal8Bit ().data () << std::endl;
265
- } else
317
+
318
+ mError = QString ( tr (" HTTP response completed, however there was an error: %1" ) )
319
+ .arg ( http->errorString () );
320
+ }
321
+ else
266
322
{
267
323
std::cout << " QgsHttpTransaction::dataFinished - no error." << std::endl;
268
324
}
@@ -272,7 +328,7 @@ void QgsHttpTransaction::dataFinished( int id, bool error )
272
328
httpresponse = http->readAll ();
273
329
274
330
httpactive = FALSE ;
275
-
331
+
276
332
}
277
333
278
334
void QgsHttpTransaction::dataStateChanged ( int state )
@@ -282,6 +338,9 @@ void QgsHttpTransaction::dataStateChanged( int state )
282
338
std::cout << " QgsHttpTransaction::dataStateChanged to " << state << " ." << std::endl << " " ;
283
339
#endif
284
340
341
+ // We saw something come back, therefore restart the watchdog timer
342
+ mWatchdogTimer ->start (NETWORK_TIMEOUT_MSEC);
343
+
285
344
switch (state)
286
345
{
287
346
case Q3Http::Unconnected:
@@ -350,6 +409,26 @@ void QgsHttpTransaction::dataStateChanged( int state )
350
409
}
351
410
352
411
412
+ void QgsHttpTransaction::networkTimedOut ()
413
+ {
414
+
415
+ #ifdef QGISDEBUG
416
+ std::cout << " QgsHttpTransaction::networkTimedOut: entering." << std::endl;
417
+ #endif
418
+
419
+ mError = QString (tr (" Network timed out after %1 seconds of inactivity.\n "
420
+ " This may be a problem in your network connection or at the WMS server." )
421
+ ).arg (NETWORK_TIMEOUT_MSEC/1000 );
422
+
423
+ httpactive = FALSE ;
424
+
425
+ #ifdef QGISDEBUG
426
+ std::cout << " QgsHttpTransaction::networkTimedOut: exiting." << std::endl;
427
+ #endif
428
+
429
+ }
430
+
431
+
353
432
QString QgsHttpTransaction::errorString ()
354
433
{
355
434
return mError ;
0 commit comments