]> git.sur5r.net Git - minitube/blob - src/networkaccess.cpp
Imported Upstream version 1.4.1
[minitube] / src / networkaccess.cpp
1 #include "networkaccess.h"
2 #include "constants.h"
3 #include <QtGui>
4
5 namespace The {
6     NetworkAccess* http();
7 }
8
9 /*
10 const QString USER_AGENT = QString(Constants::APP_NAME)
11                            + " " + Constants::VERSION
12                            + " (" + Constants::WEBSITE + ")";
13 */
14
15 const QString USER_AGENT = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10";
16
17 NetworkReply::NetworkReply(QNetworkReply *networkReply) : QObject(networkReply) {
18     this->networkReply = networkReply;
19
20     // monitor downloadProgress to impl timeout
21     connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
22             SLOT(downloadProgress(qint64,qint64)), Qt::AutoConnection);
23
24     readTimeoutTimer = new QTimer(this);
25     readTimeoutTimer->setInterval(5000);
26     readTimeoutTimer->setSingleShot(true);
27     connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()));
28     readTimeoutTimer->start();
29 }
30
31 void NetworkReply::finished() {
32
33     QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
34     if (redirection.isValid()) {
35
36         // qDebug() << "Redirect!"; // << redirection;
37
38         QNetworkReply *redirectReply = The::http()->simpleGet(redirection, networkReply->operation());
39
40         setParent(redirectReply);
41         networkReply->deleteLater();
42         networkReply = redirectReply;
43
44         // when the request is finished we'll invoke the target method
45         connect(networkReply, SIGNAL(finished()), this, SLOT(finished()), Qt::AutoConnection);
46
47         // monitor downloadProgress to impl timeout
48         connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
49                 SLOT(downloadProgress(qint64,qint64)), Qt::AutoConnection);
50         readTimeoutTimer->start();
51
52         // error signal
53         connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
54                 SLOT(requestError(QNetworkReply::NetworkError)));
55
56         return;
57     }
58
59
60     emit finished(networkReply);
61
62     // get the HTTP response body
63     QByteArray bytes = networkReply->readAll();
64
65     emit data(bytes);
66
67     // bye bye my reply
68     // this will also delete this NetworkReply as the QNetworkReply is its parent
69     networkReply->deleteLater();
70 }
71
72 void NetworkReply::requestError(QNetworkReply::NetworkError /* code */) {
73     emit error(networkReply);
74 }
75
76 void NetworkReply::downloadProgress(qint64 bytesReceived, qint64 /* bytesTotal */) {
77     // qDebug() << "Downloading" << bytesReceived << bytesTotal;
78     if (bytesReceived > 0) {
79         readTimeoutTimer->stop();
80         disconnect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
81                    this, SLOT(downloadProgress(qint64,qint64)));
82     }
83 }
84
85 void NetworkReply::readTimeout() {
86     // qDebug() << "HTTP read timeout" << networkReply->url();
87     networkReply->disconnect();
88     networkReply->abort();
89
90     QNetworkReply *retryReply = The::http()->simpleGet(networkReply->url(), networkReply->operation());
91
92     setParent(retryReply);
93     networkReply->deleteLater();
94     networkReply = retryReply;
95
96     // when the request is finished we'll invoke the target method
97     connect(networkReply, SIGNAL(finished()), this, SLOT(finished()), Qt::AutoConnection);
98
99     // monitor downloadProgress to impl timeout
100     connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
101             SLOT(downloadProgress(qint64,qint64)), Qt::AutoConnection);
102     readTimeoutTimer->start();
103
104     // error signal
105     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
106             SLOT(requestError(QNetworkReply::NetworkError)));
107
108     // emit error(networkReply);
109 }
110
111 /* --- NetworkAccess --- */
112
113 NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
114
115 QNetworkReply* NetworkAccess::manualGet(QNetworkRequest request, int operation) {
116
117     QNetworkAccessManager *manager = The::networkAccessManager();
118     // manager->setCookieJar(new QNetworkCookieJar());
119
120     QNetworkReply *networkReply;
121     switch (operation) {
122
123     case QNetworkAccessManager::GetOperation:
124         qDebug() << "GET" << request.url().toEncoded();
125         networkReply = manager->get(request);
126         break;
127
128     case QNetworkAccessManager::HeadOperation:
129         qDebug() << "HEAD" << request.url().toEncoded();
130         networkReply = manager->head(request);
131         break;
132
133     default:
134         qDebug() << "Unknown operation:" << operation;
135         return 0;
136
137     }
138
139     // error handling
140     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
141             this, SLOT(error(QNetworkReply::NetworkError)));
142
143     return networkReply;
144 }
145
146 QNetworkReply* NetworkAccess::simpleGet(QUrl url, int operation) {
147
148     QNetworkRequest request(url);
149     request.setRawHeader("User-Agent", USER_AGENT.toUtf8());
150     request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
151     request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
152     request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
153     request.setRawHeader("Connection", "Keep-Alive");
154
155     return manualGet(request, operation);
156 }
157
158 NetworkReply* NetworkAccess::get(const QUrl url) {
159
160     QNetworkReply *networkReply = simpleGet(url);
161     NetworkReply *reply = new NetworkReply(networkReply);
162
163     // error signal
164     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
165             reply, SLOT(requestError(QNetworkReply::NetworkError)));
166
167     // when the request is finished we'll invoke the target method
168     connect(networkReply, SIGNAL(finished()), reply, SLOT(finished()), Qt::AutoConnection);
169
170     return reply;
171
172 }
173
174 NetworkReply* NetworkAccess::head(const QUrl url) {
175
176     QNetworkReply *networkReply = simpleGet(url, QNetworkAccessManager::HeadOperation);
177     NetworkReply *reply = new NetworkReply(networkReply);
178
179     // error signal
180     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
181             reply, SLOT(requestError(QNetworkReply::NetworkError)));
182
183     // when the request is finished we'll invoke the target method
184     connect(networkReply, SIGNAL(finished()), reply, SLOT(finished()), Qt::AutoConnection);
185
186     return reply;
187
188 }
189
190 /*** sync ***/
191
192
193 QNetworkReply* NetworkAccess::syncGet(QUrl url) {
194
195     working = true;
196
197     networkReply = simpleGet(url);
198     connect(networkReply, SIGNAL(metaDataChanged()),
199             this, SLOT(syncMetaDataChanged()), Qt::AutoConnection);
200     connect(networkReply, SIGNAL(finished()),
201             this, SLOT(syncFinished()), Qt::AutoConnection);
202     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
203             this, SLOT(error(QNetworkReply::NetworkError)));
204
205     // A little trick to make this function blocking
206     while (working) {
207         // Do something else, maybe even network processing events
208         qApp->processEvents();
209     }
210
211     networkReply->deleteLater();
212     return networkReply;
213
214 }
215
216 void NetworkAccess::syncMetaDataChanged() {
217
218     QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
219     if (redirection.isValid()) {
220
221         qDebug() << "Redirect" << redirection;
222         networkReply->deleteLater();
223         syncGet(redirection);
224
225         /*
226         QNetworkAccessManager *manager = The::networkAccessManager();
227         networkReply->deleteLater();
228         networkReply = manager->get(QNetworkRequest(redirection));
229         connect(networkReply, SIGNAL(metaDataChanged()),
230                 this, SLOT(metaDataChanged()), Qt::AutoConnection);
231         connect(networkReply, SIGNAL(finished()),
232                 this, SLOT(finished()), Qt::AutoConnection);
233         */
234     }
235
236 }
237
238 void NetworkAccess::syncFinished() {
239     // got it!
240     working = false;
241 }
242
243 void NetworkAccess::error(QNetworkReply::NetworkError code) {
244     // get the QNetworkReply that sent the signal
245     QNetworkReply *networkReply = static_cast<QNetworkReply *>(sender());
246     if (!networkReply) {
247         qDebug() << "Cannot get sender";
248         return;
249     }
250
251     // Ignore HEADs
252     if (networkReply->operation() == QNetworkAccessManager::HeadOperation)
253         return;
254
255     // report the error in the status bar
256     QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(qApp->topLevelWidgets().first());
257     if (mainWindow) mainWindow->statusBar()->showMessage(
258             tr("Network error: %1").arg(networkReply->errorString()));
259
260     qDebug() << "Network error:" << networkReply->errorString() << code;
261
262     networkReply->deleteLater();
263 }
264
265 QByteArray NetworkAccess::syncGetBytes(QUrl url) {
266     return syncGet(url)->readAll();
267 }
268
269 QString NetworkAccess::syncGetString(QUrl url) {
270     return QString::fromUtf8(syncGetBytes(url));
271 }