~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to iris/src/xmpp/cutestuff/httppoll.cpp

  • Committer: Package Import Robot
  • Author(s): Jan Niehusmann
  • Date: 2014-07-01 21:49:34 UTC
  • mfrom: (6.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20140701214934-gt4dkgm94byi4vnn
Tags: 0.15-1
* New upstream version
* set debhelper compat level to 9
* set Standards-Version to 3.9.5 (no further changes)
* add lintian override regarding license-problem-non-free-RFC
* use qconf to regenerate configure script
* implement hardening using buildflags instead of hardening-wrapper

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * httppoll.cpp - HTTP polling proxy
3
 
 * Copyright (C) 2003  Justin Karneges
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 *
19
 
 */
20
 
 
21
 
#include "httppoll.h"
22
 
 
23
 
#include <QUrl>
24
 
#include <qstringlist.h>
25
 
#include <qtimer.h>
26
 
#include <qpointer.h>
27
 
#include <QtCrypto>
28
 
#include <QByteArray>
29
 
#include <stdlib.h>
30
 
#include "bsocket.h"
31
 
 
32
 
#ifdef PROX_DEBUG
33
 
#include <stdio.h>
34
 
#endif
35
 
 
36
 
#define POLL_KEYS 64
37
 
 
38
 
// CS_NAMESPACE_BEGIN
39
 
 
40
 
static QByteArray randomArray(int size)
41
 
{
42
 
        QByteArray a;
43
 
  a.resize(size);
44
 
        for(int n = 0; n < size; ++n)
45
 
                a[n] = (char)(256.0*rand()/(RAND_MAX+1.0));
46
 
        return a;
47
 
}
48
 
 
49
 
//----------------------------------------------------------------------------
50
 
// HttpPoll
51
 
//----------------------------------------------------------------------------
52
 
static QString hpk(int n, const QString &s)
53
 
{
54
 
        if(n == 0)
55
 
                return s;
56
 
        else
57
 
                return QCA::Base64().arrayToString( QCA::Hash("sha1").hash( hpk(n - 1, s).toLatin1() ).toByteArray() );
58
 
}
59
 
 
60
 
class HttpPoll::Private
61
 
{
62
 
public:
63
 
        Private() {}
64
 
 
65
 
        HttpProxyPost http;
66
 
        QString host;
67
 
        int port;
68
 
        QString user, pass;
69
 
        QString url;
70
 
        bool use_proxy;
71
 
 
72
 
        QByteArray out;
73
 
 
74
 
        int state;
75
 
        bool closing;
76
 
        QString ident;
77
 
 
78
 
        QTimer *t;
79
 
 
80
 
        QString key[POLL_KEYS];
81
 
        int key_n;
82
 
 
83
 
        int polltime;
84
 
};
85
 
 
86
 
HttpPoll::HttpPoll(QObject *parent)
87
 
:ByteStream(parent)
88
 
{
89
 
        d = new Private;
90
 
 
91
 
        d->polltime = 30;
92
 
        d->t = new QTimer;
93
 
  d->t->setSingleShot(true);
94
 
        connect(d->t, SIGNAL(timeout()), SLOT(do_sync()));
95
 
 
96
 
        connect(&d->http, SIGNAL(result()), SLOT(http_result()));
97
 
        connect(&d->http, SIGNAL(error(int)), SLOT(http_error(int)));
98
 
 
99
 
        reset(true);
100
 
}
101
 
 
102
 
HttpPoll::~HttpPoll()
103
 
{
104
 
        reset(true);
105
 
        delete d->t;
106
 
        delete d;
107
 
}
108
 
 
109
 
void HttpPoll::reset(bool clear)
110
 
{
111
 
        if(d->http.isActive())
112
 
                d->http.stop();
113
 
        if(clear)
114
 
                clearReadBuffer();
115
 
        clearWriteBuffer();
116
 
        d->out.resize(0);
117
 
        d->state = 0;
118
 
        d->closing = false;
119
 
        d->t->stop();
120
 
}
121
 
 
122
 
void HttpPoll::setAuth(const QString &user, const QString &pass)
123
 
{
124
 
        d->user = user;
125
 
        d->pass = pass;
126
 
}
127
 
 
128
 
void HttpPoll::connectToUrl(const QString &url)
129
 
{
130
 
        connectToHost("", 0, url);
131
 
}
132
 
 
133
 
void HttpPoll::connectToHost(const QString &proxyHost, int proxyPort, const QString &url)
134
 
{
135
 
        reset(true);
136
 
 
137
 
        // using proxy?
138
 
        if(!proxyHost.isEmpty()) {
139
 
                d->host = proxyHost;
140
 
                d->port = proxyPort;
141
 
                d->url = url;
142
 
                d->use_proxy = true;
143
 
        }
144
 
        else {
145
 
                QUrl u = url;
146
 
                d->host = u.host();
147
 
                if(u.port() != -1)
148
 
                        d->port = u.port();
149
 
                else
150
 
                        d->port = 80;
151
 
                d->url = u.path() + "?" + u.encodedQuery();
152
 
                d->use_proxy = false;
153
 
        }
154
 
 
155
 
        resetKey();
156
 
        bool last;
157
 
        QString key = getKey(&last);
158
 
 
159
 
#ifdef PROX_DEBUG
160
 
        fprintf(stderr, "HttpPoll: Connecting to %s:%d [%s]", d->host.latin1(), d->port, d->url.latin1());
161
 
        if(d->user.isEmpty())
162
 
                fprintf(stderr, "\n");
163
 
        else
164
 
                fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1());
165
 
#endif
166
 
        QPointer<QObject> self = this;
167
 
        syncStarted();
168
 
        if(!self)
169
 
                return;
170
 
 
171
 
        d->state = 1;
172
 
        d->http.setAuth(d->user, d->pass);
173
 
        d->http.post(d->host, d->port, d->url, makePacket("0", key, "", QByteArray()), d->use_proxy);
174
 
}
175
 
 
176
 
QByteArray HttpPoll::makePacket(const QString &ident, const QString &key, const QString &newkey, const QByteArray &block)
177
 
{
178
 
        QString str = ident;
179
 
        if(!key.isEmpty()) {
180
 
                str += ';';
181
 
                str += key;
182
 
        }
183
 
        if(!newkey.isEmpty()) {
184
 
                str += ';';
185
 
                str += newkey;
186
 
        }
187
 
        str += ',';
188
 
        QByteArray cs = str.toLatin1();
189
 
        int len = cs.length();
190
 
 
191
 
        QByteArray a;
192
 
  a.resize(len + block.size());
193
 
        memcpy(a.data(), cs.data(), len);
194
 
        memcpy(a.data() + len, block.data(), block.size());
195
 
        return a;
196
 
}
197
 
 
198
 
int HttpPoll::pollInterval() const
199
 
{
200
 
        return d->polltime;
201
 
}
202
 
 
203
 
void HttpPoll::setPollInterval(int seconds)
204
 
{
205
 
        d->polltime = seconds;
206
 
}
207
 
 
208
 
bool HttpPoll::isOpen() const
209
 
{
210
 
        return (d->state == 2 ? true: false);
211
 
}
212
 
 
213
 
void HttpPoll::close()
214
 
{
215
 
        if(d->state == 0 || d->closing)
216
 
                return;
217
 
 
218
 
        if(bytesToWrite() == 0)
219
 
                reset();
220
 
        else
221
 
                d->closing = true;
222
 
}
223
 
 
224
 
void HttpPoll::http_result()
225
 
{
226
 
        // check for death :)
227
 
        QPointer<QObject> self = this;
228
 
        syncFinished();
229
 
        if(!self)
230
 
                return;
231
 
 
232
 
        // get id and packet
233
 
        QString id;
234
 
        QString cookie = d->http.getHeader("Set-Cookie");
235
 
        int n = cookie.indexOf("ID=");
236
 
        if(n == -1) {
237
 
                reset();
238
 
                error(ErrRead);
239
 
                return;
240
 
        }
241
 
        n += 3;
242
 
        int n2 = cookie.indexOf(';', n);
243
 
        if(n2 != -1)
244
 
                id = cookie.mid(n, n2-n);
245
 
        else
246
 
                id = cookie.mid(n);
247
 
        QByteArray block = d->http.body();
248
 
 
249
 
        // session error?
250
 
        if(id.right(2) == ":0") {
251
 
                if(id == "0:0" && d->state == 2) {
252
 
                        reset();
253
 
                        connectionClosed();
254
 
                        return;
255
 
                }
256
 
                else {
257
 
                        reset();
258
 
                        error(ErrRead);
259
 
                        return;
260
 
                }
261
 
        }
262
 
 
263
 
        d->ident = id;
264
 
        bool justNowConnected = false;
265
 
        if(d->state == 1) {
266
 
                d->state = 2;
267
 
                justNowConnected = true;
268
 
        }
269
 
 
270
 
        // sync up again soon
271
 
        if(bytesToWrite() > 0 || !d->closing) {
272
 
                d->t->start(d->polltime * 1000);
273
 
  }
274
 
 
275
 
        // connecting
276
 
        if(justNowConnected) {
277
 
                connected();
278
 
        }
279
 
        else {
280
 
                if(!d->out.isEmpty()) {
281
 
                        int x = d->out.size();
282
 
                        d->out.resize(0);
283
 
                        takeWrite(x);
284
 
                        bytesWritten(x);
285
 
                }
286
 
        }
287
 
 
288
 
        if(!self)
289
 
                return;
290
 
 
291
 
        if(!block.isEmpty()) {
292
 
                appendRead(block);
293
 
                readyRead();
294
 
        }
295
 
 
296
 
        if(!self)
297
 
                return;
298
 
 
299
 
        if(bytesToWrite() > 0) {
300
 
                do_sync();
301
 
        }
302
 
        else {
303
 
                if(d->closing) {
304
 
                        reset();
305
 
                        delayedCloseFinished();
306
 
                        return;
307
 
                }
308
 
        }
309
 
}
310
 
 
311
 
void HttpPoll::http_error(int x)
312
 
{
313
 
        reset();
314
 
        if(x == HttpProxyPost::ErrConnectionRefused)
315
 
                error(ErrConnectionRefused);
316
 
        else if(x == HttpProxyPost::ErrHostNotFound)
317
 
                error(ErrHostNotFound);
318
 
        else if(x == HttpProxyPost::ErrSocket)
319
 
                error(ErrRead);
320
 
        else if(x == HttpProxyPost::ErrProxyConnect)
321
 
                error(ErrProxyConnect);
322
 
        else if(x == HttpProxyPost::ErrProxyNeg)
323
 
                error(ErrProxyNeg);
324
 
        else if(x == HttpProxyPost::ErrProxyAuth)
325
 
                error(ErrProxyAuth);
326
 
}
327
 
 
328
 
int HttpPoll::tryWrite()
329
 
{
330
 
        if(!d->http.isActive())
331
 
                do_sync();
332
 
        return 0;
333
 
}
334
 
 
335
 
void HttpPoll::do_sync()
336
 
{
337
 
        if(d->http.isActive())
338
 
                return;
339
 
 
340
 
        d->t->stop();
341
 
        d->out = takeWrite(0, false);
342
 
 
343
 
        bool last;
344
 
        QString key = getKey(&last);
345
 
        QString newkey;
346
 
        if(last) {
347
 
                resetKey();
348
 
                newkey = getKey(&last);
349
 
        }
350
 
 
351
 
        QPointer<QObject> self = this;
352
 
        syncStarted();
353
 
        if(!self)
354
 
                return;
355
 
 
356
 
        d->http.post(d->host, d->port, d->url, makePacket(d->ident, key, newkey, d->out), d->use_proxy);
357
 
}
358
 
 
359
 
void HttpPoll::resetKey()
360
 
{
361
 
#ifdef PROX_DEBUG
362
 
        fprintf(stderr, "HttpPoll: reset key!\n");
363
 
#endif
364
 
        QByteArray a = randomArray(64);
365
 
        QString str = QString::fromLatin1(a.data(), a.size());
366
 
 
367
 
        d->key_n = POLL_KEYS;
368
 
        for(int n = 0; n < POLL_KEYS; ++n)
369
 
                d->key[n] = hpk(n+1, str);
370
 
}
371
 
 
372
 
const QString & HttpPoll::getKey(bool *last)
373
 
{
374
 
        *last = false;
375
 
        --(d->key_n);
376
 
        if(d->key_n == 0)
377
 
                *last = true;
378
 
        return d->key[d->key_n];
379
 
}
380
 
 
381
 
 
382
 
//----------------------------------------------------------------------------
383
 
// HttpProxyPost
384
 
//----------------------------------------------------------------------------
385
 
static QString extractLine(QByteArray *buf, bool *found)
386
 
{
387
 
        // scan for newline
388
 
        int n;
389
 
        for(n = 0; n < (int)buf->size()-1; ++n) {
390
 
                if(buf->at(n) == '\r' && buf->at(n+1) == '\n') {
391
 
                        QByteArray cstr;
392
 
                        cstr.resize(n);
393
 
                        memcpy(cstr.data(), buf->data(), n);
394
 
                        n += 2; // hack off CR/LF
395
 
 
396
 
                        memmove(buf->data(), buf->data() + n, buf->size() - n);
397
 
                        buf->resize(buf->size() - n);
398
 
                        QString s = QString::fromUtf8(cstr);
399
 
 
400
 
                        if(found)
401
 
                                *found = true;
402
 
                        return s;
403
 
                }
404
 
        }
405
 
 
406
 
        if(found)
407
 
                *found = false;
408
 
        return "";
409
 
}
410
 
 
411
 
static bool extractMainHeader(const QString &line, QString *proto, int *code, QString *msg)
412
 
{
413
 
        int n = line.indexOf(' ');
414
 
        if(n == -1)
415
 
                return false;
416
 
        if(proto)
417
 
                *proto = line.mid(0, n);
418
 
        ++n;
419
 
        int n2 = line.indexOf(' ', n);
420
 
        if(n2 == -1)
421
 
                return false;
422
 
        if(code)
423
 
                *code = line.mid(n, n2-n).toInt();
424
 
        n = n2+1;
425
 
        if(msg)
426
 
                *msg = line.mid(n);
427
 
        return true;
428
 
}
429
 
 
430
 
class HttpProxyPost::Private
431
 
{
432
 
public:
433
 
        Private() {}
434
 
 
435
 
        BSocket sock;
436
 
        QByteArray postdata, recvBuf, body;
437
 
        QString url;
438
 
        QString user, pass;
439
 
        bool inHeader;
440
 
        QStringList headerLines;
441
 
        bool asProxy;
442
 
        QString host;
443
 
};
444
 
 
445
 
HttpProxyPost::HttpProxyPost(QObject *parent)
446
 
:QObject(parent)
447
 
{
448
 
        d = new Private;
449
 
        connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected()));
450
 
        connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
451
 
        connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
452
 
        connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int)));
453
 
        reset(true);
454
 
}
455
 
 
456
 
HttpProxyPost::~HttpProxyPost()
457
 
{
458
 
        reset(true);
459
 
        delete d;
460
 
}
461
 
 
462
 
void HttpProxyPost::reset(bool clear)
463
 
{
464
 
        if(d->sock.state() != BSocket::Idle)
465
 
                d->sock.close();
466
 
        d->recvBuf.resize(0);
467
 
        if(clear)
468
 
                d->body.resize(0);
469
 
}
470
 
 
471
 
void HttpProxyPost::setAuth(const QString &user, const QString &pass)
472
 
{
473
 
        d->user = user;
474
 
        d->pass = pass;
475
 
}
476
 
 
477
 
bool HttpProxyPost::isActive() const
478
 
{
479
 
        return (d->sock.state() == BSocket::Idle ? false: true);
480
 
}
481
 
 
482
 
void HttpProxyPost::post(const QString &proxyHost, int proxyPort, const QString &url, const QByteArray &data, bool asProxy)
483
 
{
484
 
        reset(true);
485
 
 
486
 
        d->host = proxyHost;
487
 
        d->url = url;
488
 
        d->postdata = data;
489
 
        d->asProxy = asProxy;
490
 
 
491
 
#ifdef PROX_DEBUG
492
 
        fprintf(stderr, "HttpProxyPost: Connecting to %s:%d", proxyHost.latin1(), proxyPort);
493
 
        if(d->user.isEmpty())
494
 
                fprintf(stderr, "\n");
495
 
        else
496
 
                fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1());
497
 
#endif
498
 
        d->sock.connectToHost(proxyHost, proxyPort);
499
 
}
500
 
 
501
 
void HttpProxyPost::stop()
502
 
{
503
 
        reset();
504
 
}
505
 
 
506
 
QByteArray HttpProxyPost::body() const
507
 
{
508
 
        return d->body;
509
 
}
510
 
 
511
 
QString HttpProxyPost::getHeader(const QString &var) const
512
 
{
513
 
        for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) {
514
 
                const QString &s = *it;
515
 
                int n = s.indexOf(": ");
516
 
                if(n == -1)
517
 
                        continue;
518
 
                QString v = s.mid(0, n);
519
 
                if(v.toLower() == var.toLower())
520
 
                        return s.mid(n+2);
521
 
        }
522
 
        return "";
523
 
}
524
 
 
525
 
void HttpProxyPost::sock_connected()
526
 
{
527
 
#ifdef PROX_DEBUG
528
 
        fprintf(stderr, "HttpProxyPost: Connected\n");
529
 
#endif
530
 
        d->inHeader = true;
531
 
        d->headerLines.clear();
532
 
 
533
 
        QUrl u = d->url;
534
 
 
535
 
        // connected, now send the request
536
 
        QString s;
537
 
        s += QString("POST ") + d->url + " HTTP/1.0\r\n";
538
 
        if(d->asProxy) {
539
 
                if(!d->user.isEmpty()) {
540
 
                        QString str = d->user + ':' + d->pass;
541
 
                        s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n";
542
 
                }
543
 
                s += "Pragma: no-cache\r\n";
544
 
                s += QString("Host: ") + u.host() + "\r\n";
545
 
        }
546
 
        else {
547
 
                s += QString("Host: ") + d->host + "\r\n";
548
 
        }
549
 
        s += "Content-Type: application/x-www-form-urlencoded\r\n";
550
 
        s += QString("Content-Length: ") + QString::number(d->postdata.size()) + "\r\n";
551
 
        s += "\r\n";
552
 
 
553
 
        // write request
554
 
        d->sock.write(s.toUtf8());
555
 
 
556
 
        // write postdata
557
 
        d->sock.write(d->postdata);
558
 
}
559
 
 
560
 
void HttpProxyPost::sock_connectionClosed()
561
 
{
562
 
        d->body = d->recvBuf;
563
 
        reset();
564
 
        result();
565
 
}
566
 
 
567
 
void HttpProxyPost::sock_readyRead()
568
 
{
569
 
        QByteArray block = d->sock.read();
570
 
        ByteStream::appendArray(&d->recvBuf, block);
571
 
 
572
 
        if(d->inHeader) {
573
 
                // grab available lines
574
 
                while(1) {
575
 
                        bool found;
576
 
                        QString line = extractLine(&d->recvBuf, &found);
577
 
                        if(!found)
578
 
                                break;
579
 
                        if(line.isEmpty()) {
580
 
                                d->inHeader = false;
581
 
                                break;
582
 
                        }
583
 
                        d->headerLines += line;
584
 
                }
585
 
 
586
 
                // done with grabbing the header?
587
 
                if(!d->inHeader) {
588
 
                        QString str = d->headerLines.first();
589
 
                        d->headerLines.takeFirst();
590
 
 
591
 
                        QString proto;
592
 
                        int code;
593
 
                        QString msg;
594
 
                        if(!extractMainHeader(str, &proto, &code, &msg)) {
595
 
#ifdef PROX_DEBUG
596
 
                                fprintf(stderr, "HttpProxyPost: invalid header!\n");
597
 
#endif
598
 
                                reset(true);
599
 
                                error(ErrProxyNeg);
600
 
                                return;
601
 
                        }
602
 
                        else {
603
 
#ifdef PROX_DEBUG
604
 
                                fprintf(stderr, "HttpProxyPost: header proto=[%s] code=[%d] msg=[%s]\n", proto.latin1(), code, msg.latin1());
605
 
                                for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it)
606
 
                                        fprintf(stderr, "HttpProxyPost: * [%s]\n", (*it).latin1());
607
 
#endif
608
 
                        }
609
 
 
610
 
                        if(code == 200) { // OK
611
 
#ifdef PROX_DEBUG
612
 
                                fprintf(stderr, "HttpProxyPost: << Success >>\n");
613
 
#endif
614
 
                        }
615
 
                        else {
616
 
                                int err;
617
 
                                QString errStr;
618
 
                                if(code == 407) { // Authentication failed
619
 
                                        err = ErrProxyAuth;
620
 
                                        errStr = tr("Authentication failed");
621
 
                                }
622
 
                                else if(code == 404) { // Host not found
623
 
                                        err = ErrHostNotFound;
624
 
                                        errStr = tr("Host not found");
625
 
                                }
626
 
                                else if(code == 403) { // Access denied
627
 
                                        err = ErrProxyNeg;
628
 
                                        errStr = tr("Access denied");
629
 
                                }
630
 
                                else if(code == 503) { // Connection refused
631
 
                                        err = ErrConnectionRefused;
632
 
                                        errStr = tr("Connection refused");
633
 
                                }
634
 
                                else { // invalid reply
635
 
                                        err = ErrProxyNeg;
636
 
                                        errStr = tr("Invalid reply");
637
 
                                }
638
 
 
639
 
#ifdef PROX_DEBUG
640
 
                                fprintf(stderr, "HttpProxyPost: << Error >> [%s]\n", errStr.latin1());
641
 
#endif
642
 
                                reset(true);
643
 
                                error(err);
644
 
                                return;
645
 
                        }
646
 
                }
647
 
        }
648
 
}
649
 
 
650
 
void HttpProxyPost::sock_error(int x)
651
 
{
652
 
#ifdef PROX_DEBUG
653
 
        fprintf(stderr, "HttpProxyPost: socket error: %d\n", x);
654
 
#endif
655
 
        reset(true);
656
 
        if(x == BSocket::ErrHostNotFound)
657
 
                error(ErrProxyConnect);
658
 
        else if(x == BSocket::ErrConnectionRefused)
659
 
                error(ErrProxyConnect);
660
 
        else if(x == BSocket::ErrRead)
661
 
                error(ErrProxyNeg);
662
 
}
663
 
 
664
 
//----------------------------------------------------------------------------
665
 
// HttpProxyGetStream
666
 
//----------------------------------------------------------------------------
667
 
class HttpProxyGetStream::Private
668
 
{
669
 
public:
670
 
        Private() {}
671
 
 
672
 
        BSocket sock;
673
 
        QByteArray recvBuf;
674
 
        QString url;
675
 
        QString user, pass;
676
 
        bool inHeader;
677
 
        QStringList headerLines;
678
 
        bool use_ssl;
679
 
        bool asProxy;
680
 
        QString host;
681
 
        int length;
682
 
 
683
 
        QCA::TLS *tls;
684
 
};
685
 
 
686
 
HttpProxyGetStream::HttpProxyGetStream(QObject *parent)
687
 
:QObject(parent)
688
 
{
689
 
        d = new Private;
690
 
        d->tls = 0;
691
 
        connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected()));
692
 
        connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
693
 
        connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
694
 
        connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int)));
695
 
        reset(true);
696
 
}
697
 
 
698
 
HttpProxyGetStream::~HttpProxyGetStream()
699
 
{
700
 
        reset(true);
701
 
        delete d;
702
 
}
703
 
 
704
 
void HttpProxyGetStream::reset(bool /*clear*/)
705
 
{
706
 
        if(d->tls) {
707
 
                delete d->tls;
708
 
                d->tls = 0;
709
 
        }
710
 
        if(d->sock.state() != BSocket::Idle)
711
 
                d->sock.close();
712
 
        d->recvBuf.resize(0);
713
 
        //if(clear)
714
 
        //      d->body.resize(0);
715
 
        d->length = -1;
716
 
}
717
 
 
718
 
void HttpProxyGetStream::setAuth(const QString &user, const QString &pass)
719
 
{
720
 
        d->user = user;
721
 
        d->pass = pass;
722
 
}
723
 
 
724
 
bool HttpProxyGetStream::isActive() const
725
 
{
726
 
        return (d->sock.state() == BSocket::Idle ? false: true);
727
 
}
728
 
 
729
 
void HttpProxyGetStream::get(const QString &proxyHost, int proxyPort, const QString &url, bool ssl, bool asProxy)
730
 
{
731
 
        reset(true);
732
 
 
733
 
        d->host = proxyHost;
734
 
        d->url = url;
735
 
        d->use_ssl = ssl;
736
 
        d->asProxy = asProxy;
737
 
 
738
 
#ifdef PROX_DEBUG
739
 
        fprintf(stderr, "HttpProxyGetStream: Connecting to %s:%d", proxyHost.latin1(), proxyPort);
740
 
        if(d->user.isEmpty())
741
 
                fprintf(stderr, "\n");
742
 
        else
743
 
                fprintf(stderr, ", auth {%s,%s}\n", d->user.latin1(), d->pass.latin1());
744
 
#endif
745
 
        d->sock.connectToHost(proxyHost, proxyPort);
746
 
}
747
 
 
748
 
void HttpProxyGetStream::stop()
749
 
{
750
 
        reset();
751
 
}
752
 
 
753
 
QString HttpProxyGetStream::getHeader(const QString &var) const
754
 
{
755
 
        for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) {
756
 
                const QString &s = *it;
757
 
                int n = s.indexOf(": ");
758
 
                if(n == -1)
759
 
                        continue;
760
 
                QString v = s.mid(0, n);
761
 
                if(v.toLower() == var.toLower())
762
 
                        return s.mid(n+2);
763
 
        }
764
 
        return "";
765
 
}
766
 
 
767
 
int HttpProxyGetStream::length() const
768
 
{
769
 
        return d->length;
770
 
}
771
 
 
772
 
void HttpProxyGetStream::sock_connected()
773
 
{
774
 
#ifdef PROX_DEBUG
775
 
        fprintf(stderr, "HttpProxyGetStream: Connected\n");
776
 
#endif
777
 
        if(d->use_ssl) {
778
 
                d->tls = new QCA::TLS;
779
 
                connect(d->tls, SIGNAL(readyRead()), SLOT(tls_readyRead()));
780
 
                connect(d->tls, SIGNAL(readyReadOutgoing()), SLOT(tls_readyReadOutgoing()));
781
 
                connect(d->tls, SIGNAL(error()), SLOT(tls_error()));
782
 
                d->tls->startClient();
783
 
        }
784
 
 
785
 
        d->inHeader = true;
786
 
        d->headerLines.clear();
787
 
 
788
 
        QUrl u = d->url;
789
 
 
790
 
        // connected, now send the request
791
 
        QString s;
792
 
        s += QString("GET ") + d->url + " HTTP/1.0\r\n";
793
 
        if(d->asProxy) {
794
 
                if(!d->user.isEmpty()) {
795
 
                        QString str = d->user + ':' + d->pass;
796
 
                        s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n";
797
 
                }
798
 
                s += "Pragma: no-cache\r\n";
799
 
                s += QString("Host: ") + u.host() + "\r\n";
800
 
        }
801
 
        else {
802
 
                s += QString("Host: ") + d->host + "\r\n";
803
 
        }
804
 
        s += "\r\n";
805
 
 
806
 
        // write request
807
 
        if(d->use_ssl)
808
 
                d->tls->write(s.toUtf8());
809
 
        else
810
 
                d->sock.write(s.toUtf8());
811
 
}
812
 
 
813
 
void HttpProxyGetStream::sock_connectionClosed()
814
 
{
815
 
        //d->body = d->recvBuf;
816
 
        reset();
817
 
        emit finished();
818
 
}
819
 
 
820
 
void HttpProxyGetStream::sock_readyRead()
821
 
{
822
 
        QByteArray block = d->sock.read();
823
 
 
824
 
        if(d->use_ssl)
825
 
                d->tls->writeIncoming(block);
826
 
        else
827
 
                processData(block);
828
 
}
829
 
 
830
 
void HttpProxyGetStream::processData(const QByteArray &block)
831
 
{
832
 
        printf("processData: %d bytes\n", block.size());
833
 
        if(!d->inHeader) {
834
 
                emit dataReady(block);
835
 
                return;
836
 
        }
837
 
 
838
 
        ByteStream::appendArray(&d->recvBuf, block);
839
 
 
840
 
        if(d->inHeader) {
841
 
                // grab available lines
842
 
                while(1) {
843
 
                        bool found;
844
 
                        QString line = extractLine(&d->recvBuf, &found);
845
 
                        if(!found)
846
 
                                break;
847
 
                        if(line.isEmpty()) {
848
 
                                printf("empty line\n");
849
 
                                d->inHeader = false;
850
 
                                break;
851
 
                        }
852
 
                        d->headerLines += line;
853
 
                        printf("headerLine: [%s]\n", qPrintable(line));
854
 
                }
855
 
 
856
 
                // done with grabbing the header?
857
 
                if(!d->inHeader) {
858
 
                        QString str = d->headerLines.first();
859
 
                        d->headerLines.takeFirst();
860
 
 
861
 
                        QString proto;
862
 
                        int code;
863
 
                        QString msg;
864
 
                        if(!extractMainHeader(str, &proto, &code, &msg)) {
865
 
#ifdef PROX_DEBUG
866
 
                                fprintf(stderr, "HttpProxyGetStream: invalid header!\n");
867
 
#endif
868
 
                                reset(true);
869
 
                                error(ErrProxyNeg);
870
 
                                return;
871
 
                        }
872
 
                        else {
873
 
#ifdef PROX_DEBUG
874
 
                                fprintf(stderr, "HttpProxyGetStream: header proto=[%s] code=[%d] msg=[%s]\n", proto.latin1(), code, msg.latin1());
875
 
                                for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it)
876
 
                                        fprintf(stderr, "HttpProxyGetStream: * [%s]\n", (*it).latin1());
877
 
#endif
878
 
                        }
879
 
 
880
 
                        if(code == 200) { // OK
881
 
#ifdef PROX_DEBUG
882
 
                                fprintf(stderr, "HttpProxyGetStream: << Success >>\n");
883
 
#endif
884
 
 
885
 
                                bool ok;
886
 
                                int x = getHeader("Content-Length").toInt(&ok);
887
 
                                if(ok)
888
 
                                        d->length = x;
889
 
 
890
 
                                QPointer<QObject> self = this;
891
 
                                emit handshaken();
892
 
                                if(!self)
893
 
                                        return;
894
 
                        }
895
 
                        else {
896
 
                                int err;
897
 
                                QString errStr;
898
 
                                if(code == 407) { // Authentication failed
899
 
                                        err = ErrProxyAuth;
900
 
                                        errStr = tr("Authentication failed");
901
 
                                }
902
 
                                else if(code == 404) { // Host not found
903
 
                                        err = ErrHostNotFound;
904
 
                                        errStr = tr("Host not found");
905
 
                                }
906
 
                                else if(code == 403) { // Access denied
907
 
                                        err = ErrProxyNeg;
908
 
                                        errStr = tr("Access denied");
909
 
                                }
910
 
                                else if(code == 503) { // Connection refused
911
 
                                        err = ErrConnectionRefused;
912
 
                                        errStr = tr("Connection refused");
913
 
                                }
914
 
                                else { // invalid reply
915
 
                                        err = ErrProxyNeg;
916
 
                                        errStr = tr("Invalid reply");
917
 
                                }
918
 
 
919
 
#ifdef PROX_DEBUG
920
 
                                fprintf(stderr, "HttpProxyGetStream: << Error >> [%s]\n", errStr.latin1());
921
 
#endif
922
 
                                reset(true);
923
 
                                error(err);
924
 
                                return;
925
 
                        }
926
 
 
927
 
                        if(!d->recvBuf.isEmpty()) {
928
 
                                QByteArray a = d->recvBuf;
929
 
                                d->recvBuf.clear();
930
 
                                emit dataReady(a);
931
 
                        }
932
 
                }
933
 
        }
934
 
}
935
 
 
936
 
void HttpProxyGetStream::sock_error(int x)
937
 
{
938
 
#ifdef PROX_DEBUG
939
 
        fprintf(stderr, "HttpProxyGetStream: socket error: %d\n", x);
940
 
#endif
941
 
        reset(true);
942
 
        if(x == BSocket::ErrHostNotFound)
943
 
                error(ErrProxyConnect);
944
 
        else if(x == BSocket::ErrConnectionRefused)
945
 
                error(ErrProxyConnect);
946
 
        else if(x == BSocket::ErrRead)
947
 
                error(ErrProxyNeg);
948
 
}
949
 
 
950
 
void HttpProxyGetStream::tls_readyRead()
951
 
{
952
 
        //printf("tls_readyRead\n");
953
 
        processData(d->tls->read());
954
 
}
955
 
 
956
 
void HttpProxyGetStream::tls_readyReadOutgoing()
957
 
{
958
 
        //printf("tls_readyReadOutgoing\n");
959
 
        d->sock.write(d->tls->readOutgoing());
960
 
}
961
 
 
962
 
void HttpProxyGetStream::tls_error()
963
 
{
964
 
#ifdef PROX_DEBUG
965
 
        fprintf(stderr, "HttpProxyGetStream: ssl error: %d\n", d->tls->errorCode());
966
 
#endif
967
 
        reset(true);
968
 
        error(ErrConnectionRefused); // FIXME: bogus error
969
 
}
970
 
 
971
 
// CS_NAMESPACE_END