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