Russian Qt Forum

Qt => Работа с сетью => Тема начата: eldar85 от Декабрь 12, 2010, 21:22



Название: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 21:22
Добрый день. Столкнулся с такой проблемой - работаю с сетью через qnetworkaccessmanager. программка должна загружать страничку сжатую в gzip, а вот распаковать ее не получается.
Причем страничка обязательно должна быть сжата ( в заголовке запроса должен быть request.setRawHeader("Accept-Encoding", "gzip");  ) потому что иначе ответ пустой. Есть ли специальный функции у Qt для расспаковки таких страниц?


Название: Re: qnetworkaccessmanager и gzip
Отправлено: BRE от Декабрь 12, 2010, 21:25
Есть ли специальный функции у Qt для расспаковки таких страниц?
Попробуй использовать:
QByteArray qUncompress ( const QByteArray & data )


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 21:27
пробовал, выдает ошибку  qUncompress: Z_DATA_ERROR: Input data is corrupted


Название: Re: qnetworkaccessmanager и gzip
Отправлено: BRE от Декабрь 12, 2010, 21:30
пробовал, выдает ошибку  qUncompress: Z_DATA_ERROR: Input data is corrupted
Ну тогда попробуй саму библиотеку gzip.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 21:31
Вот присылаемый сервером заголовок:

Date:  Sun, 12 Dec 2010 18:28:10 GMT
Server:  Apache/2
X-Powered-By:  PHP/5.2.14
Expires:  Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control:  no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma:  no-cache
Vary:  Accept-Encoding,User-Agent
Content-Encoding:  gzip
Content-Length:  20
Keep-Alive:  timeout=1, max=100
Connection:  Keep-Alive
Content-Type:  text/html


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 21:33
такого ни разу не пробовал, можно подробнее???
Но ведь webkit как то же распаковывает такие страницы, ниужли сторонними библиотеками...


Название: Re: qnetworkaccessmanager и gzip
Отправлено: BRE от Декабрь 12, 2010, 21:36
Это про qUncompress:
Цитировать
Note: If you want to use this function to uncompress external data compressed using zlib, you first need to prepend four bytes to the byte array that contain the expected length (as an unsigned integer) of the uncompressed data encoded in big-endian order (most significant byte first).


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 21:46
как я понял нужно добавить в начало 4 байта информации об ожидаемой длине принимаего контента? Но у меня приходит Content-Length:  20, получается мне сервер всего 20 байт присылает?


Название: Re: qnetworkaccessmanager и gzip
Отправлено: BRE от Декабрь 12, 2010, 21:50
Но ведь webkit как то же распаковывает такие страницы, ниужли сторонними библиотеками...
Вообще Qt и так собирается с zlib, а вот доступ к ее функционалу ограничен функциями qCompress/qUncompress.
Посмотри реализацию этих функций.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: SimpleSunny от Декабрь 12, 2010, 22:03
Если используете QNAM, то он автоматически распаковывает сжатые страницы, и заботится об этом не нужно.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 12, 2010, 22:31
Вот так я и хочу, сейчас поищу инфу про этот QNAM


Название: Re: qnetworkaccessmanager и gzip
Отправлено: SimpleSunny от Декабрь 12, 2010, 22:41
QNetworkAccessManager


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 15, 2010, 15:56
и все же я не разобрался, какая же функция у QNetworkAccessManager расспаковывает сжатые данные???


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 15, 2010, 16:20
Цитировать
    request.setUrl(QUrl(load_url));
    request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.2.12) Gecko/20101026 MRA 5.7 (build 03773) Firefox/3.6.12");
    request.setRawHeader("Accept-Encoding", "gzip");


    if(!referer.isEmpty())
        request.setRawHeader( "Referer", referer );

    if(!cookie.isEmpty())
        request.setRawHeader( "Cookie", cookie);

    if(!proxy.isEmpty() && with_proxy)
    {
        ip_port = proxy.split(":");

        if( ip_port.length() == 2 )
        {
            tmp = ip_port[1];
            port = tmp.toInt();

            if( http_socks5 )
                manager.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, ip_port[0], port));
            else
                manager.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, ip_port[0], port));
        }
    }

    if(post_data.isEmpty())
        reply = manager.get( request );
    else
        reply = manager.post( request, post_data );


    QObject::connect( reply, SIGNAL( finished() ), &loop, SLOT( quit() ) );
    QObject::connect( &timer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );

    timer.start(30000);
    loop.exec();

    cookie_loaded = reply->rawHeader("Set-Cookie");
    location = reply->rawHeader("Location");

    buf = reply->readAll();

вот часть моего класса работы с сетью, но он у меня не расспаковывает автоматически gzip или возможно что то сделал я не так ???


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 17, 2010, 06:58
хмм и в правду QNAM расспаковывает все, проблема была в моем классе, я после пост запроса не очищал переменную post_data - жесть... странно но я долго не мог заметить этот баг... в программе задействовано достаточно не мало кода, а этот класс достаточно свежий и еще хорошо не протестил его))) но хоть убей не видел этого бага, пока не спя двое суток подряд уже в состоянии "никаком" не взгленул таки на эти строки
Цитировать
if(post_data.isEmpty())
        reply = manager.get( request );
    else
        reply = manager.post( request, post_data );

и проследил весь класс))) получается после первого пост запроса все остальные запросы тоже шли постом)))))))) фак... а я думал из за распаковки такая кака приходит)))))))


Название: Re: qnetworkaccessmanager и gzip
Отправлено: SimpleSunny от Декабрь 17, 2010, 08:36
В таких случаях снифер бы помог быстрее решить проблему ;)


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 17, 2010, 21:23
у меня стоит wireshrak но он почему то видет только если через кабель выходишь в сеть, через фай фай зараза не отслеживает запросы...
все же хоть я и решил проблему с пост и гет запросами, проблема осталась

как такое может быть, приходит от сервера ответ с заголовком

Date:  Fri, 17 Dec 2010 11:47:18 GMT
Server:  Apache/2
X-Powered-By:  PHP/5.2.14
Expires:  Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control:  private, no-cache
Pragma:  no-cache
Vary:  Accept-Encoding,User-Agent
Content-Encoding:  gzip
Content-Length:  4177
Keep-Alive:  timeout=1, max=98
Connection:  Keep-Alive
Content-Type:  text/html; charset=windows-1251

и тело

"‹"

причем в снифере смотрел, приходит тип присылаемых данных text/html а на деле как будто что то бинарное, хотя судя по заголовку длинна html странички должна быть Content-Length:  4177


Название: Re: qnetworkaccessmanager и gzip
Отправлено: SimpleSunny от Декабрь 17, 2010, 21:42
Может ошибка какая-то, и данные не докачиваются. reply->error() что говорит.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 17, 2010, 21:48
0 ошибок как не странно.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 17, 2010, 21:53
возможно что то с сайтом, кто нить попробуйте у себя загрузить http://awmproxy.com  у меня все страницы этого сайта такую фигню выдают...


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 17, 2010, 22:01
ну наконец то решил проблему)) спасибо SimpleSunny и  BRE за помощь)

убрал вот эту строку из хидера запрос  request.setRawHeader("Accept-Encoding", "gzip,deflate");
но все же есть сайты которые не дают ответа если эту строку не указать, то как же быть с ними...


Название: Re: qnetworkaccessmanager и gzip
Отправлено: SimpleSunny от Декабрь 17, 2010, 23:09
Deflate обещают в 4.7.2 добавить (http://bugreports.qt.nokia.com/browse/QTBUG-13191), сейчас можно довольствоваться только gzip.


Название: Re: qnetworkaccessmanager и gzip
Отправлено: eldar85 от Декабрь 18, 2010, 00:44
так оно и так не расспаковывается request.setRawHeader("Accept-Encoding", "gzip");


Название: Re: qnetworkaccessmanager и gzip
Отправлено: thechicho от Октябрь 27, 2011, 21:55
.pro
Код
C++ (Qt)
INCLUDEPATH += $$[QT_INSTALL_PREFIX]/src/3rdparty/zlib

.h
Код
C++ (Qt)
QByteArray uncompress(const QByteArray &);

.cpp
Код
C++ (Qt)
#include <zlib.h>
 
   QNetworkAccessManager qnam;
 
   QNetworkProxy proxy;
   if (proxySOCKS5) {
       proxy.setType(QNetworkProxy::Socks5Proxy);
   } else if (proxyHTTP) {
       proxy.setType(QNetworkProxy::HttpProxy);
   }
 
   if (proxyOne.isEmpty() && !proxyNO) {
       qDebug() << "Нема прокси"; return;
   }
   if (!proxyNO) {
   QStringList proxyList = proxyOne.trimmed().split(":");
 
   QString proxyHostName = proxyList[0];
   quint16 proxyPort = QString(proxyList[1]).toInt();
 
   proxy.setHostName(proxyHostName);
   proxy.setPort(proxyPort);
 
   qnam.setProxy(proxy);
   }
 
   RemadedNetworkCookieJar *cookieJar = new RemadedNetworkCookieJar();
   qnam.setCookieJar(cookieJar);
 
   QNetworkRequest request;
   request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1");
   request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
   request.setRawHeader("Accept-Language", "ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3");
   request.setRawHeader("Accept-Encoding", "gzip, deflate");
   request.setRawHeader("Accept-Charset", "windows-1251,utf-8;q=0.7,*;q=0.7");
   request.setRawHeader("Connection", "keep-alive");
   request.setUrl(QUrl("http://mail.ru"));
 
   QNetworkReply *reply = qnam.get(request);
 
   QEventLoop loop;
   connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
   loop.exec();
 
   reply->deleteLater();
   if(reply->error() != QNetworkReply::NoError) {
       qDebug() << reply->errorString();
   }
 
   QString answer = QString::fromLocal8Bit(uncompress(reply->readAll())); // если кодировка сайта Windows-1251. если локаль в другой кодировке, будут иероглифы. как без привязки к локале из Windows-1251 преобразовать не догнал
   QString answer = QString::fromUtf8(uncompress(reply->readAll())); // charset=UTF-8
 
 
QByteArray Class::uncompress(const QByteArray &data)
{
   if (data.size() <= 4) {
       qWarning("gUncompress: Input data is truncated");
       return QByteArray();
   }
 
   QByteArray result;
 
   int ret;
   z_stream strm;
   static const int CHUNK_SIZE = 1024;
   char out[CHUNK_SIZE];
 
   /* allocate inflate state */
   strm.zalloc = Z_NULL;
   strm.zfree = Z_NULL;
   strm.opaque = Z_NULL;
   strm.avail_in = data.size();
   strm.next_in = (Bytef*)(data.data());
 
   ret = inflateInit2(&strm, 15 +  32); // gzip decoding
   if (ret != Z_OK)
       return QByteArray();
 
   // run inflate()
   do {
       strm.avail_out = CHUNK_SIZE;
       strm.next_out = (Bytef*)(out);
 
       ret = inflate(&strm, Z_NO_FLUSH);
       Q_ASSERT(ret != Z_STREAM_ERROR);  // state not clobbered
 
       switch (ret) {
       case Z_NEED_DICT:
           ret = Z_DATA_ERROR;     // and fall through
       case Z_DATA_ERROR:
       case Z_MEM_ERROR:
           (void)inflateEnd(&strm);
           return QByteArray();
       }
 
       result.append(out, CHUNK_SIZE - strm.avail_out);
   } while (strm.avail_out == 0);
 
   // clean up and return
   inflateEnd(&strm);
   return result;
}

источник: http://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data (http://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data)