diff options
Diffstat (limited to 'rbutil/rbutilqt/base')
-rw-r--r-- | rbutil/rbutilqt/base/httpget.cpp | 444 | ||||
-rw-r--r-- | rbutil/rbutilqt/base/httpget.h | 80 |
2 files changed, 162 insertions, 362 deletions
diff --git a/rbutil/rbutilqt/base/httpget.cpp b/rbutil/rbutilqt/base/httpget.cpp index 8005d4848b..e6b9eb4d3c 100644 --- a/rbutil/rbutilqt/base/httpget.cpp +++ b/rbutil/rbutilqt/base/httpget.cpp | |||
@@ -6,7 +6,7 @@ | |||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * | 8 | * |
9 | * Copyright (C) 2007 by Dominik Riebeling | 9 | * Copyright (C) 2013 by Dominik Riebeling |
10 | * | 10 | * |
11 | * All files in this archive are subject to the GNU General Public License. | 11 | * All files in this archive are subject to the GNU General Public License. |
12 | * See the file COPYING in the source tree root for full license agreement. | 12 | * See the file COPYING in the source tree root for full license agreement. |
@@ -16,52 +16,31 @@ | |||
16 | * | 16 | * |
17 | ****************************************************************************/ | 17 | ****************************************************************************/ |
18 | 18 | ||
19 | #include <QtCore> | ||
20 | #include <QtNetwork> | 19 | #include <QtNetwork> |
21 | #include <QtDebug> | 20 | #include <QtDebug> |
22 | 21 | ||
22 | #include <QNetworkAccessManager> | ||
23 | #include <QNetworkRequest> | ||
24 | |||
23 | #include "httpget.h" | 25 | #include "httpget.h" |
24 | 26 | ||
25 | QDir HttpGet::m_globalCache; //< global cach path value for new objects | ||
26 | QUrl HttpGet::m_globalProxy; //< global proxy value for new objects | ||
27 | QString HttpGet::m_globalUserAgent; //< globally set user agent for requests | 27 | QString HttpGet::m_globalUserAgent; //< globally set user agent for requests |
28 | QDir HttpGet::m_globalCache; //< global cach path value for new objects | ||
29 | QNetworkProxy HttpGet::m_globalProxy; | ||
28 | 30 | ||
29 | HttpGet::HttpGet(QObject *parent) | 31 | HttpGet::HttpGet(QObject *parent) |
30 | : QObject(parent) | 32 | : QObject(parent) |
31 | { | 33 | { |
32 | outputToBuffer = true; | 34 | m_mgr = new QNetworkAccessManager(this); |
33 | m_cached = false; | 35 | m_cache = NULL; |
34 | getRequest = -1; | ||
35 | headRequest = -1; | ||
36 | // if a request is cancelled before a reponse is available return some | ||
37 | // hint about this in the http response instead of nonsense. | ||
38 | m_response = -1; | ||
39 | m_useproxy = false; | ||
40 | |||
41 | // default to global proxy / cache if not empty. | ||
42 | // proxy is automatically enabled, disable it by setting an empty proxy | ||
43 | // cache is enabled to be in line, can get disabled with setCache(bool) | ||
44 | if(!m_globalProxy.isEmpty()) | ||
45 | setProxy(m_globalProxy); | ||
46 | m_usecache = false; | ||
47 | m_cachedir = m_globalCache; | 36 | m_cachedir = m_globalCache; |
48 | 37 | setCache(true); | |
49 | m_serverTimestamp = QDateTime(); | 38 | connect(m_mgr, SIGNAL(finished(QNetworkReply*)), |
50 | 39 | this, SLOT(requestFinished(QNetworkReply*))); | |
51 | connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool))); | 40 | m_outputFile = NULL; |
52 | connect(&http, SIGNAL(dataReadProgress(int, int)), | 41 | m_lastServerTimestamp = QDateTime(); |
53 | this, SIGNAL(dataReadProgress(int, int))); | 42 | m_proxy = QNetworkProxy::NoProxy; |
54 | connect(&http, SIGNAL(requestFinished(int, bool)), | 43 | m_reply = NULL; |
55 | this, SLOT(httpFinished(int, bool))); | ||
56 | connect(&http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), | ||
57 | this, SLOT(httpResponseHeader(const QHttpResponseHeader&))); | ||
58 | // connect(&http, SIGNAL(stateChanged(int)), this, SLOT(httpState(int))); | ||
59 | connect(&http, SIGNAL(requestStarted(int)), this, SLOT(httpStarted(int))); | ||
60 | |||
61 | connect(&http, SIGNAL(readyRead(const QHttpResponseHeader&)), | ||
62 | this, SLOT(httpResponseHeader(const QHttpResponseHeader&))); | ||
63 | connect(this, SIGNAL(headerFinished()), this, SLOT(getFileFinish())); | ||
64 | |||
65 | } | 44 | } |
66 | 45 | ||
67 | 46 | ||
@@ -69,10 +48,10 @@ HttpGet::HttpGet(QObject *parent) | |||
69 | // @param d new directory to use as cache path | 48 | // @param d new directory to use as cache path |
70 | void HttpGet::setCache(const QDir& d) | 49 | void HttpGet::setCache(const QDir& d) |
71 | { | 50 | { |
72 | m_cachedir = d; | 51 | if(m_cache && m_cachedir == d.absolutePath()) |
73 | bool result; | 52 | return; |
74 | result = initializeCache(d); | 53 | m_cachedir = d.absolutePath(); |
75 | m_usecache = result; | 54 | setCache(true); |
76 | } | 55 | } |
77 | 56 | ||
78 | 57 | ||
@@ -81,29 +60,29 @@ void HttpGet::setCache(const QDir& d) | |||
81 | */ | 60 | */ |
82 | void HttpGet::setCache(bool c) | 61 | void HttpGet::setCache(bool c) |
83 | { | 62 | { |
84 | m_usecache = c; | 63 | // don't change cache if it's already (un)set. |
85 | // make sure cache is initialized | 64 | if(c && m_cache) return; |
86 | if(c) | 65 | if(!c && !m_cache) return; |
87 | m_usecache = initializeCache(m_cachedir); | 66 | // don't delete the old cache directly, it might still be in use. Just |
88 | } | 67 | // instruct it to delete itself later. |
68 | if(m_cache) m_cache->deleteLater(); | ||
69 | m_cache = NULL; | ||
89 | 70 | ||
71 | QString path = m_cachedir.absolutePath(); | ||
90 | 72 | ||
91 | bool HttpGet::initializeCache(const QDir& d) | 73 | if(!c || m_cachedir.absolutePath().isEmpty()) { |
92 | { | 74 | qDebug() << "[HttpGet] disabling download cache"; |
93 | bool result; | ||
94 | QString p = d.absolutePath() + "/rbutil-cache"; | ||
95 | if(QFileInfo(d.absolutePath()).isDir()) | ||
96 | { | ||
97 | if(!QFileInfo(p).isDir()) | ||
98 | result = d.mkdir("rbutil-cache"); | ||
99 | else | ||
100 | result = true; | ||
101 | } | 75 | } |
102 | else | 76 | else { |
103 | result = false; | 77 | // append the cache path to make it unique in case the path points to |
104 | 78 | // the system temporary path. In that case using it directly might | |
105 | return result; | 79 | // cause problems. Extra path also used in configure dialog. |
106 | 80 | path += "/rbutil-cache"; | |
81 | qDebug() << "[HttpGet] setting cache folder to" << path; | ||
82 | m_cache = new QNetworkDiskCache(this); | ||
83 | m_cache->setCacheDirectory(path); | ||
84 | } | ||
85 | m_mgr->setCache(m_cache); | ||
107 | } | 86 | } |
108 | 87 | ||
109 | 88 | ||
@@ -112,324 +91,133 @@ bool HttpGet::initializeCache(const QDir& d) | |||
112 | */ | 91 | */ |
113 | QByteArray HttpGet::readAll() | 92 | QByteArray HttpGet::readAll() |
114 | { | 93 | { |
115 | return dataBuffer; | 94 | return m_data; |
116 | } | 95 | } |
117 | 96 | ||
118 | 97 | ||
119 | void HttpGet::setProxy(const QUrl &proxy) | 98 | void HttpGet::setProxy(const QUrl &proxy) |
120 | { | 99 | { |
121 | m_proxy = proxy; | 100 | qDebug() << "[HttpGet] Proxy set to" << proxy; |
122 | m_useproxy = true; | 101 | m_proxy.setType(QNetworkProxy::HttpProxy); |
123 | http.setProxy(m_proxy.host(), m_proxy.port(), | 102 | m_proxy.setHostName(proxy.host()); |
124 | m_proxy.userName(), m_proxy.password()); | 103 | m_proxy.setPort(proxy.port()); |
104 | m_proxy.setUser(proxy.userName()); | ||
105 | m_proxy.setPassword(proxy.password()); | ||
106 | m_mgr->setProxy(m_proxy); | ||
125 | } | 107 | } |
126 | 108 | ||
127 | 109 | ||
128 | void HttpGet::setProxy(bool enable) | 110 | void HttpGet::setProxy(bool enable) |
129 | { | 111 | { |
130 | if(enable) { | 112 | if(enable) m_mgr->setProxy(m_proxy); |
131 | m_useproxy = true; | 113 | else m_mgr->setProxy(QNetworkProxy::NoProxy); |
132 | http.setProxy(m_proxy.host(), m_proxy.port(), | ||
133 | m_proxy.userName(), m_proxy.password()); | ||
134 | } | ||
135 | else { | ||
136 | m_useproxy = false; | ||
137 | http.setProxy("", 0); | ||
138 | } | ||
139 | } | 114 | } |
140 | 115 | ||
141 | 116 | ||
142 | void HttpGet::setFile(QFile *file) | 117 | void HttpGet::setFile(QFile *file) |
143 | { | 118 | { |
144 | outputFile = file; | 119 | m_outputFile = file; |
145 | outputToBuffer = false; | ||
146 | } | 120 | } |
147 | 121 | ||
148 | 122 | ||
149 | void HttpGet::abort() | 123 | void HttpGet::abort() |
150 | { | 124 | { |
151 | qDebug() << "[HTTP] Aborting requests, pending:" << http.hasPendingRequests(); | 125 | if(m_reply) m_reply->abort(); |
152 | http.abort(); | 126 | } |
153 | if(!outputToBuffer) | 127 | |
154 | outputFile->close(); | 128 | |
155 | } | 129 | void HttpGet::requestFinished(QNetworkReply* reply) |
156 | 130 | { | |
157 | 131 | m_lastStatusCode | |
158 | bool HttpGet::getFile(const QUrl &url) | 132 | = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); |
159 | { | 133 | qDebug() << "[HttpGet] Request finished, status code:" << m_lastStatusCode; |
160 | if (!url.isValid()) { | 134 | m_lastServerTimestamp |
161 | qDebug() << "[HTTP] Error: Invalid URL" << endl; | 135 | = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toLocalTime(); |
162 | return false; | 136 | qDebug() << "[HttpGet] Data from cache:" |
163 | } | 137 | << reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); |
164 | 138 | m_lastRequestCached = | |
165 | if (url.scheme() != "http") { | 139 | reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); |
166 | qDebug() << "[HTTP] Error: URL must start with 'http:'" << endl; | 140 | if(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) { |
167 | return false; | 141 | // handle relative URLs using QUrl::resolved() |
168 | } | 142 | QUrl org = reply->request().url(); |
169 | 143 | QUrl url = QUrl(org).resolved( | |
170 | if (url.path().isEmpty()) { | 144 | reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()); |
171 | qDebug() << "[HTTP] Error: URL has no path" << endl; | 145 | // reconstruct query |
172 | return false; | 146 | #if QT_VERSION < 0x050000 |
173 | } | 147 | QList<QPair<QByteArray, QByteArray> > qitms = org.encodedQueryItems(); |
174 | m_serverTimestamp = QDateTime(); | 148 | for(int i = 0; i < qitms.size(); ++i) |
175 | // if no output file was set write to buffer | 149 | url.addEncodedQueryItem(qitms.at(i).first, qitms.at(i).second); |
176 | if(!outputToBuffer) { | 150 | #else |
177 | if (!outputFile->open(QIODevice::ReadWrite)) { | 151 | url.setQuery(org.query()); |
178 | qDebug() << "[HTTP] Error: Cannot open " << qPrintable(outputFile->fileName()) | 152 | #endif |
179 | << " for writing: " << qPrintable(outputFile->errorString()); | 153 | qDebug() << "[HttpGet] Redirected to" << url; |
180 | return false; | 154 | startRequest(url); |
181 | } | 155 | return; |
182 | } | ||
183 | else { | ||
184 | // output to buffer. Make sure buffer is empty so no old data gets | ||
185 | // returned in case the object is reused. | ||
186 | dataBuffer.clear(); | ||
187 | } | ||
188 | qDebug() << "[HTTP] GET URI" << url.toEncoded(); | ||
189 | // create request | ||
190 | http.setHost(url.host(), url.port(80)); | ||
191 | // construct query (if any) | ||
192 | QList<QPair<QString, QString> > qitems = url.queryItems(); | ||
193 | if(url.hasQuery()) { | ||
194 | m_query = "?"; | ||
195 | for(int i = 0; i < qitems.size(); i++) | ||
196 | m_query += QUrl::toPercentEncoding(qitems.at(i).first, "/") + "=" | ||
197 | + QUrl::toPercentEncoding(qitems.at(i).second, "/") + "&"; | ||
198 | } | ||
199 | |||
200 | // create hash used for caching | ||
201 | m_hash = QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex(); | ||
202 | m_cachefile = m_cachedir.absolutePath() + "/rbutil-cache/" + m_hash; | ||
203 | // RFC2616: the absoluteURI form must get used when the request is being | ||
204 | // sent to a proxy. | ||
205 | m_path.clear(); | ||
206 | if(m_useproxy) | ||
207 | m_path = url.scheme() + "://" + url.host(); | ||
208 | m_path += QString(QUrl::toPercentEncoding(url.path(), "/")); | ||
209 | |||
210 | // construct request header | ||
211 | m_header.setValue("Host", url.host()); | ||
212 | m_header.setValue("User-Agent", m_globalUserAgent); | ||
213 | m_header.setValue("Connection", "Keep-Alive"); | ||
214 | |||
215 | if(!m_usecache || !QFileInfo(m_cachefile).exists()) { | ||
216 | getFileFinish(); | ||
217 | } | ||
218 | else { | ||
219 | // schedule HTTP header request | ||
220 | m_header.setRequest("HEAD", m_path + m_query); | ||
221 | headRequest = http.request(m_header); | ||
222 | qDebug() << "[HTTP] HEAD scheduled: " << headRequest; | ||
223 | } | 156 | } |
224 | 157 | else if(m_lastStatusCode == 200) { | |
225 | return true; | 158 | m_data = reply->readAll(); |
226 | } | 159 | if(m_outputFile && m_outputFile->open(QIODevice::WriteOnly)) { |
227 | 160 | m_outputFile->write(m_data); | |
228 | 161 | m_outputFile->close(); | |
229 | void HttpGet::getFileFinish() | ||
230 | { | ||
231 | QString indexFile = m_cachedir.absolutePath() + "/rbutil-cache/cache.txt"; | ||
232 | if(m_usecache) { | ||
233 | // check if the file is present in cache | ||
234 | QFileInfo cachefile = QFileInfo(m_cachefile); | ||
235 | if(cachefile.isReadable() | ||
236 | && cachefile.size() > 0 | ||
237 | && cachefile.lastModified() > m_serverTimestamp) { | ||
238 | |||
239 | qDebug() << "[HTTP] Cache: up-to-date file found:" << m_cachefile; | ||
240 | |||
241 | getRequest = -1; | ||
242 | QFile c(m_cachefile); | ||
243 | if(!outputToBuffer) { | ||
244 | qDebug() << "[HTTP] Cache: copying file to output" | ||
245 | << outputFile->fileName(); | ||
246 | c.open(QIODevice::ReadOnly); | ||
247 | outputFile->open(QIODevice::ReadWrite); | ||
248 | outputFile->write(c.readAll()); | ||
249 | outputFile->close(); | ||
250 | c.close(); | ||
251 | } | ||
252 | else { | ||
253 | qDebug() << "[HTTP] Cache: reading file into buffer"; | ||
254 | c.open(QIODevice::ReadOnly); | ||
255 | dataBuffer = c.readAll(); | ||
256 | c.close(); | ||
257 | } | ||
258 | m_response = 200; // fake "200 OK" HTTP response | ||
259 | m_cached = true; | ||
260 | httpDone(false); // we're done now. Handle http "done" signal. | ||
261 | return; | ||
262 | } | 162 | } |
263 | else { | 163 | emit done(false); |
264 | // unlink old cache file | ||
265 | if(cachefile.isReadable()) { | ||
266 | QFile(m_cachefile).remove(); | ||
267 | qDebug() << "[HTTP] Cache: outdated, timestamp:" | ||
268 | << cachefile.lastModified(); | ||
269 | } | ||
270 | qDebug() << "[HTTP] Cache: caching as" << m_cachefile; | ||
271 | // update cache index file | ||
272 | QFile idxFile(indexFile); | ||
273 | idxFile.open(QIODevice::ReadOnly); | ||
274 | QByteArray currLine; | ||
275 | do { | ||
276 | QByteArray currLine = idxFile.readLine(1000); | ||
277 | if(currLine.startsWith(m_hash.toUtf8())) | ||
278 | break; | ||
279 | } while(!currLine.isEmpty()); | ||
280 | idxFile.close(); | ||
281 | if(currLine.isEmpty()) { | ||
282 | idxFile.open(QIODevice::Append); | ||
283 | QString outline = m_hash + "\t" + m_header.value("Host") + "\t" | ||
284 | + m_path + "\t" + m_query + "\n"; | ||
285 | idxFile.write(outline.toUtf8()); | ||
286 | idxFile.close(); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | } | ||
291 | else { | ||
292 | qDebug() << "[HTTP] cache DISABLED"; | ||
293 | } | ||
294 | // schedule GET request | ||
295 | |||
296 | m_header.setRequest("GET", m_path + m_query); | ||
297 | if(outputToBuffer) { | ||
298 | qDebug() << "[HTTP] downloading to buffer."; | ||
299 | getRequest = http.request(m_header); | ||
300 | } | 164 | } |
301 | else { | 165 | else { |
302 | qDebug() << "[HTTP] downloading to file:" | 166 | m_data.clear(); |
303 | << qPrintable(outputFile->fileName()); | 167 | emit done(true); |
304 | getRequest = http.request(m_header, 0, outputFile); | ||
305 | } | 168 | } |
306 | qDebug() << "[HTTP] GET scheduled: " << getRequest; | 169 | reply->deleteLater(); |
307 | 170 | m_reply = NULL; | |
308 | return; | ||
309 | } | 171 | } |
310 | 172 | ||
311 | 173 | ||
312 | void HttpGet::httpDone(bool error) | 174 | void HttpGet::downloadProgress(qint64 received, qint64 total) |
313 | { | 175 | { |
314 | if (error) { | 176 | emit dataReadProgress((int)received, (int)total); |
315 | qDebug() << "[HTTP] Error:" << qPrintable(http.errorString()) << httpResponse(); | ||
316 | } | ||
317 | if(!outputToBuffer) | ||
318 | outputFile->close(); | ||
319 | |||
320 | if(m_usecache && !m_cached && !error) { | ||
321 | qDebug() << "[HTTP] creating cache file" << m_cachefile; | ||
322 | QFile c(m_cachefile); | ||
323 | c.open(QIODevice::ReadWrite); | ||
324 | if(!outputToBuffer) { | ||
325 | outputFile->open(QIODevice::ReadOnly | QIODevice::Truncate); | ||
326 | c.write(outputFile->readAll()); | ||
327 | outputFile->close(); | ||
328 | } | ||
329 | else | ||
330 | c.write(dataBuffer); | ||
331 | |||
332 | c.close(); | ||
333 | } | ||
334 | // take care of concurring requests. If there is still one running, | ||
335 | // don't emit done(). That request will call this slot again. | ||
336 | if(http.currentId() == 0 && !http.hasPendingRequests()) | ||
337 | emit done(error); | ||
338 | } | 177 | } |
339 | 178 | ||
340 | 179 | ||
341 | void HttpGet::httpFinished(int id, bool error) | 180 | void HttpGet::startRequest(QUrl url) |
342 | { | 181 | { |
343 | qDebug() << "[HTTP] Request finished:" << id << "Error:" << error | 182 | qDebug() << "[HttpGet] Request started"; |
344 | << "pending requests:" << http.hasPendingRequests(); | 183 | QNetworkRequest req(url); |
345 | if(id == getRequest) { | 184 | if(!m_globalUserAgent.isEmpty()) |
346 | dataBuffer = http.readAll(); | 185 | req.setRawHeader("User-Agent", m_globalUserAgent.toLatin1()); |
347 | emit requestFinished(id, error); | ||
348 | } | ||
349 | 186 | ||
350 | QHttpResponseHeader h = http.lastResponse(); | 187 | m_reply = m_mgr->get(req); |
351 | QString date = h.value("Last-Modified").simplified(); | 188 | connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), |
352 | if(date.isEmpty()) { | 189 | this, SLOT(networkError(QNetworkReply::NetworkError))); |
353 | m_serverTimestamp = QDateTime(); // no value = invalid | 190 | connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), |
354 | if(id == headRequest) | 191 | this, SLOT(downloadProgress(qint64, qint64))); |
355 | emit headerFinished(); | ||
356 | else | ||
357 | emit requestFinished(id, error); | ||
358 | return; | ||
359 | } | ||
360 | // to successfully parse the date strip weekday and timezone | ||
361 | date.remove(0, date.indexOf(" ") + 1); | ||
362 | if(date.endsWith("GMT")) date.truncate(date.indexOf(" GMT")); | ||
363 | // distinguish input formats (see RFC1945) | ||
364 | if(date.at(0).isLetter()) // asctime format | ||
365 | m_serverTimestamp = QLocale::c().toDateTime(date, "MMM d hh:mm:ss yyyy"); | ||
366 | else // RFC 822 | ||
367 | m_serverTimestamp = QLocale::c().toDateTime(date, "dd MMM yyyy hh:mm:ss"); | ||
368 | |||
369 | qDebug() << "[HTTP] file server date:" << date | ||
370 | << "parsed:" << m_serverTimestamp; | ||
371 | |||
372 | if(id == headRequest) | ||
373 | emit headerFinished(); | ||
374 | else | ||
375 | emit requestFinished(id, error); | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | void HttpGet::httpStarted(int id) | ||
380 | { | ||
381 | qDebug() << "[HTTP] Request started: " << id << "Header req:" | ||
382 | << headRequest << "Get req:" << getRequest; | ||
383 | } | 192 | } |
384 | 193 | ||
385 | 194 | ||
386 | QString HttpGet::errorString() | 195 | void HttpGet::networkError(QNetworkReply::NetworkError error) |
387 | { | 196 | { |
388 | return http.errorString(); | 197 | qDebug() << "[HttpGet] NetworkError occured:" |
198 | << error << m_reply->errorString(); | ||
199 | m_lastErrorString = m_reply->errorString(); | ||
389 | } | 200 | } |
390 | 201 | ||
391 | 202 | ||
392 | void HttpGet::httpResponseHeader(const QHttpResponseHeader &resp) | 203 | bool HttpGet::getFile(const QUrl &url) |
393 | { | 204 | { |
394 | // if there is a network error abort all scheduled requests for | 205 | qDebug() << "[HttpGet] Get URI" << url.toString(); |
395 | // this download | 206 | m_data.clear(); |
396 | m_response = resp.statusCode(); | 207 | startRequest(url); |
397 | |||
398 | // 301 -- moved permanently | ||
399 | // 302 -- found | ||
400 | // 303 -- see other | ||
401 | // 307 -- moved temporarily | ||
402 | // in all cases, header: location has the correct address so we can follow. | ||
403 | if(m_response == 301 || m_response == 302 || m_response == 303 || m_response == 307) { | ||
404 | //abort without sending any signals | ||
405 | http.blockSignals(true); | ||
406 | http.abort(); | ||
407 | http.blockSignals(false); | ||
408 | // start new request with new url | ||
409 | qDebug() << "[HTTP] response =" << m_response << "- following"; | ||
410 | getFile(resp.value("location") + m_query); | ||
411 | } | ||
412 | else if(m_response != 200) { | ||
413 | // all other errors are fatal. | ||
414 | http.abort(); | ||
415 | qDebug() << "[HTTP] Response error:" << m_response << resp.reasonPhrase(); | ||
416 | } | ||
417 | 208 | ||
209 | return false; | ||
418 | } | 210 | } |
419 | 211 | ||
420 | 212 | ||
421 | int HttpGet::httpResponse() | 213 | QString HttpGet::errorString(void) |
422 | { | 214 | { |
423 | return m_response; | 215 | return m_lastErrorString; |
424 | } | 216 | } |
425 | 217 | ||
426 | 218 | ||
427 | void HttpGet::httpState(int state) | 219 | int HttpGet::httpResponse(void) |
428 | { | 220 | { |
429 | QString s[] = {"Unconnected", "HostLookup", "Connecting", "Sending", | 221 | return m_lastStatusCode; |
430 | "Reading", "Connected", "Closing"}; | ||
431 | if(state <= 6) | ||
432 | qDebug() << "[HTTP] State:" << s[state]; | ||
433 | else qDebug() << "[HTTP] State:" << state; | ||
434 | } | 222 | } |
435 | 223 | ||
diff --git a/rbutil/rbutilqt/base/httpget.h b/rbutil/rbutilqt/base/httpget.h index 73d3fbbaf5..2f6448a40d 100644 --- a/rbutil/rbutilqt/base/httpget.h +++ b/rbutil/rbutilqt/base/httpget.h | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <QtCore> | 25 | #include <QtCore> |
26 | #include <QtNetwork> | 26 | #include <QtNetwork> |
27 | #include <QNetworkAccessManager> | ||
27 | 28 | ||
28 | class HttpGet : public QObject | 29 | class HttpGet : public QObject |
29 | { | 30 | { |
@@ -42,14 +43,34 @@ class HttpGet : public QObject | |||
42 | int httpResponse(void); | 43 | int httpResponse(void); |
43 | QByteArray readAll(void); | 44 | QByteArray readAll(void); |
44 | bool isCached() | 45 | bool isCached() |
45 | { return m_cached; } | 46 | { return m_lastRequestCached; } |
46 | QDateTime timestamp(void) | 47 | QDateTime timestamp(void) |
47 | { return m_serverTimestamp; } | 48 | { return m_lastServerTimestamp; } |
48 | static void setGlobalCache(const QDir& d) //< set global cache path | 49 | //< set global cache path |
49 | { m_globalCache = d; } | 50 | static void setGlobalCache(const QDir& d) |
50 | static void setGlobalProxy(const QUrl& p) //< set global proxy value | 51 | { |
51 | { m_globalProxy = p; } | 52 | qDebug() << "[HttpGet] Global cache set to" << d.absolutePath(); |
52 | static void setGlobalUserAgent(const QString& u) //< set global user agent string | 53 | m_globalCache = d; |
54 | } | ||
55 | //< set global proxy value | ||
56 | static void setGlobalProxy(const QUrl& p) | ||
57 | { | ||
58 | qDebug() << "[HttpGet] setting global proxy" << p; | ||
59 | if(!p.isValid() || p.isEmpty()) { | ||
60 | HttpGet::m_globalProxy.setType(QNetworkProxy::NoProxy); | ||
61 | } | ||
62 | else { | ||
63 | HttpGet::m_globalProxy.setType(QNetworkProxy::HttpProxy); | ||
64 | HttpGet::m_globalProxy.setHostName(p.host()); | ||
65 | HttpGet::m_globalProxy.setPort(p.port()); | ||
66 | HttpGet::m_globalProxy.setUser(p.userName()); | ||
67 | HttpGet::m_globalProxy.setPassword(p.password()); | ||
68 | } | ||
69 | QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); | ||
70 | QNetworkProxy::setApplicationProxy(HttpGet::m_globalProxy); | ||
71 | } | ||
72 | //< set global user agent string | ||
73 | static void setGlobalUserAgent(const QString& u) | ||
53 | { m_globalUserAgent = u; } | 74 | { m_globalUserAgent = u; } |
54 | 75 | ||
55 | public slots: | 76 | public slots: |
@@ -62,37 +83,28 @@ class HttpGet : public QObject | |||
62 | void headerFinished(void); | 83 | void headerFinished(void); |
63 | 84 | ||
64 | private slots: | 85 | private slots: |
65 | void httpDone(bool error); | 86 | void requestFinished(QNetworkReply* reply); |
66 | void httpFinished(int, bool); | 87 | void startRequest(QUrl url); |
67 | void httpResponseHeader(const QHttpResponseHeader&); | 88 | void downloadProgress(qint64 received, qint64 total); |
68 | void httpState(int); | 89 | void networkError(QNetworkReply::NetworkError error); |
69 | void httpStarted(int); | ||
70 | void getFileFinish(void); | ||
71 | 90 | ||
72 | private: | 91 | private: |
73 | bool initializeCache(const QDir&); | 92 | static QString m_globalUserAgent; |
74 | QHttp http; //< download object | 93 | static QNetworkProxy m_globalProxy; |
75 | QFile *outputFile; | 94 | QNetworkAccessManager *m_mgr; |
76 | int m_response; //< http response | 95 | QNetworkReply *m_reply; |
77 | int getRequest; //! get file http request id | 96 | QNetworkDiskCache *m_cache; |
78 | int headRequest; //! get http header request id | ||
79 | QByteArray dataBuffer; | ||
80 | bool outputToBuffer; | ||
81 | bool m_usecache; | ||
82 | QDir m_cachedir; | 97 | QDir m_cachedir; |
83 | QString m_cachefile; // cached filename | ||
84 | bool m_cached; | ||
85 | QUrl m_proxy; | ||
86 | bool m_useproxy; | ||
87 | QDateTime m_serverTimestamp; //< timestamp of file on server | ||
88 | QString m_query; //< constructed query to pass http getter | ||
89 | QString m_path; //< constructed path to pass http getter | ||
90 | QString m_hash; //< caching hash | ||
91 | QHttpRequestHeader m_header; | ||
92 | |||
93 | static QDir m_globalCache; //< global cache path value | 98 | static QDir m_globalCache; //< global cache path value |
94 | static QUrl m_globalProxy; //< global proxy value | 99 | QByteArray m_data; |
95 | static QString m_globalUserAgent; //< global user agent string | 100 | QFile *m_outputFile; |
101 | int m_lastStatusCode; | ||
102 | QString m_lastErrorString; | ||
103 | QDateTime m_lastServerTimestamp; | ||
104 | bool m_lastRequestCached; | ||
105 | QNetworkProxy m_proxy; | ||
96 | }; | 106 | }; |
97 | 107 | ||
108 | |||
98 | #endif | 109 | #endif |
110 | |||