~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

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