source: SMSSender/lib/libgateway/src/business/HttpHelper.cpp @ 67:578192d6fe64

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