source: SMSSender/lib/libdatatypes/src/shttphelper.cpp @ 73:85d8decd3656

3.0
Last change on this file since 73:85d8decd3656 was 73:85d8decd3656, checked in by Sämy Zehnder <saemy.zehnder@…>, 8 years ago
  • Backupversion only! Before removal of QObject as parent of EException
File size: 8.0 KB
Line 
1#include "shttphelper.h"
2
3#include <QBuffer>
4#include <QDebug>
5#include <QSslError>
6#include <QThread>
7#include <QUrl>
8
9SHttpHelper::SHttpHelper() {
10    // TODO: Proxy...
11
12    http_ = new QHttp();
13
14    connect(http_, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
15            this, SLOT(responseHeaderReceived(const QHttpResponseHeader&)));
16    connect(http_, SIGNAL(requestFinished(int, bool)),
17            this, SLOT(httpRequestFinished(int, bool)));
18    connect(http_, SIGNAL(sslErrors(const QList<QSslError>&)),
19            this, SLOT(sslErrors(const QList<QSslError>&)));
20
21
22    cookieManager_ = new SHttpCookieManager(http_);
23
24    defaultHeader_ = new QHttpRequestHeader();
25    defaultHeader_->setContentType("application/x-www-form-urlencoded");
26    defaultHeader_->setValue("user-agent", "Mozilla/3.0 (compatible; SMSSender; http://www.gorrion.ch/p/smssender)"); //TODO: include version, if needed (don't generate the instance here, but in a central bchttpmanager or so)
27}
28
29SHttpHelper::~SHttpHelper() {
30    delete defaultHeader_;
31    delete cookieManager_;
32    delete http_;
33}
34
35
36QHttp* SHttpHelper::http() const {
37    return http_;
38}
39SHttpCookieManager* SHttpHelper::cookieManager() const {
40    return cookieManager_;
41}
42
43QHttpRequestHeader SHttpHelper::defaultHeader(const QUrl& url) const {
44    QHttpRequestHeader req = QHttpRequestHeader(*defaultHeader_); // return a copy, to not get touched by further modifications
45    cookieManager_->addCookieToHeader(&req, url);
46
47    return req;
48}
49
50bool SHttpHelper::get(const QString& destination, QString& requestResult, const QMap<QString, QString>& requests /* = QMap<QString, QString>() */) {
51    waitForRequest(false); // Wait until a running request has been finished
52
53    startRequest("GET", destination, requests, QMap<QString, QString>());
54    waitForRequest();
55    requestResult = this->requestResult();
56
57    return !errorOccured();
58}
59
60bool SHttpHelper::post(const QString& destination, QString& requestResult, const QMap<QString, QString>& requests /* = QMap<QString, QString>() */,
61        const QMap<QString, QString>& posts /* = QMap<QString, QString>() */)
62{
63    waitForRequest(false); // Wait until a running request has been finished
64
65    startRequest("POST", destination, requests, posts);
66    waitForRequest();
67    requestResult = this->requestResult();
68
69    return !errorOccured();
70}
71
72void SHttpHelper::startRequest(const QString& method, const QString& destination, const QMap<QString, QString>& requests /* = QMap<QString, QString>() */,
73        const QMap<QString, QString>& posts /* = QMap<QString, QString>() */)
74{
75    requestResult_   = "";
76    requestHadError_ = false;
77    lastError_       = EException();
78
79    QUrl url_ = QUrl(destination);
80
81    // Add request parameters to url_
82    QMapIterator<QString, QString> i(requests);
83    while (i.hasNext()){
84        i.next();
85        url_.addQueryItem(i.key(), i.value());
86    }
87
88    QString uri_ = url_.scheme() + "://" + url_.host() + url_.encodedPath() + "?" + url_.encodedQuery();
89    //qDebug() << uri_;
90
91    /* Create the request record */
92    request_.finished = false;
93    request_.method   = method;
94    request_.posts    = getParamStr(posts);
95
96    /* Do the request */
97    doRequest(uri_);
98}
99
100int SHttpHelper::doRequest(const QString& destination) {
101    QUrl url_ = QUrl(destination);
102
103    /* Connection */
104    QHttp::ConnectionMode mode = url_.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp;
105    http_->setHost(url_.host(), mode, url_.port(0));
106
107    if (!url_.userName().isEmpty())
108        http_->setUser(url_.userName(), url_.password());
109
110    /* Header */
111    QHttpRequestHeader header_ = defaultHeader(url_);
112    header_.setValue("Host", url_.host());
113    header_.setValue("Connection", "Keep-Alive");
114
115    QByteArray path_ = url_.encodedPath();
116    if (path_.isEmpty())
117        path_ = "/";
118
119    header_.setRequest(request_.method, path_ + "?" + url_.encodedQuery());
120
121    /* Start the request */
122    //qDebug() << destination;
123    //qDebug() << header_.toString();
124    //qDebug() << request_.posts;
125
126    request_.httpRequestId = http_->request(header_, request_.posts.toUtf8()/*, req.buffer*/);
127    qDebug() << "Started request " + QString::number(request_.httpRequestId) + ": " + request_.method + ": " + url_.path();
128
129    return request_.httpRequestId;
130}
131
132
133QString SHttpHelper::getParamStr(const QMap<QString, QString>& params) {
134    QString params_ = "";
135
136    QMapIterator<QString, QString> i(params);
137    while (i.hasNext()) {
138        i.next();
139        if (i.key().trimmed() != ""){
140            params_ += i.key() + "=" + i.value() + "&";
141        }
142    }
143    params_.remove(QRegExp("[&]$")); // remove last &
144
145    return params_;
146}
147
148void SHttpHelper::waitForRequest(bool createLoopIfNotExisting) {
149    if (!requestLoop_.isRunning() && !createLoopIfNotExisting){
150        return;
151    }
152
153    qDebug() << "Waiting for the request to finish...";
154/*    while (!request_.finished && thread()->isRunning()) {
155        thread()->wait(100);
156    }*/
157    requestLoop_.exec(QEventLoop::WaitForMoreEvents/*QEventLoop::ExcludeUserInputEvents|QEventLoop::ExcludeSocketNotifiers|QEventLoop::WaitForMoreEvents*/);
158    qDebug() << "The request finished -> continuing";
159/*    while (!request_.finished) {
160        qApp->processEvents(QEventLoop::Wai)(tForMore | QEventLoop::ExcludeUserInput);
161    }
162    qDebug() << "Starting request loop";
163    requestLoop_.exec();
164    qDebug() << "Request loop quitted";*/
165}
166
167QString SHttpHelper::requestResult() const {
168    return requestResult_;
169}
170bool SHttpHelper::errorOccured() const {
171    return requestHadError_;
172}
173EException SHttpHelper::lastError() const {
174    return lastError_;
175}
176QString SHttpHelper::lastErrorStr() const {
177    return lastError_.toString();
178}
179
180void SHttpHelper::errorOccured(int httpRequestId, const EException& exception) {
181    if (httpRequestId != request_.httpRequestId) {
182        qWarning() << "Request [" + QString::number(httpRequestId) + "] finished with an error (it is ignored, since this request is detached): " + exception.what();
183        return;
184    }
185
186    requestHadError_ = true;
187    lastError_       = exception;
188    qWarning() << "Request [" + QString::number(httpRequestId) + "] finished with an error: " + lastError().what();
189}
190
191void SHttpHelper::responseHeaderReceived(const QHttpResponseHeader& responseHeader) {
192    if (http()->currentId() != request_.httpRequestId)
193        return;
194
195    switch (responseHeader.statusCode()) {
196        case 200:
197            break;                  // Ok
198
199        case 301:                   // Moved Permanently
200        case 302:                   // Found
201        case 303:                   // See Other
202        case 307:                   // Temporary Redirect
203            qDebug() << "Have to redirect [" + QString::number(request_.httpRequestId) + "]";
204
205            request_.httpRequestId = -1; // To avoid error in httpRequestFinished
206
207            // Since the responseHeaderReceived-Slot could eventually not be called yet in cookieManager -> this would lead to a wrong header in doRequest
208            cookieManager_->processResponseHeader(responseHeader);
209
210            doRequest(responseHeader.value("location")); // Do the redirect
211            break;
212
213        default:
214            errorOccured(http_->currentId(), Http::EReadException(tr("Unknown response code")));
215            http()->abort();
216            break;
217    }
218}
219
220void SHttpHelper::httpRequestFinished(int httpRequestId, bool error) {
221     if (request_.httpRequestId != httpRequestId) {
222         qDebug() << "Request [" + QString::number(httpRequestId) + "] finished (but is not parsed, since it is detached)";
223         return;
224     }
225
226     request_.finished = true;
227     if (error) {
228         errorOccured(httpRequestId, Http::EReadException(http_->errorString()));
229     } else {
230         qDebug() << "Request [" + QString::number(httpRequestId) + "] finished";
231         requestResult_ = http_->readAll();
232     }
233     qDebug() << "Quitting request loop";
234     requestLoop_.exit(errorOccured() ? 1 : 0);
235 }
236
237void SHttpHelper::sslErrors(const QList<QSslError>& errors) {
238    errorOccured(http()->currentId(), Http::ESSLException(errors));
239}
Note: See TracBrowser for help on using the repository browser.