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

« back to all changes in this revision

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