Russian Qt Forum

Qt => Работа с сетью => Тема начата: Даниил от Август 08, 2011, 10:57



Название: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 08, 2011, 10:57
Здравствуйте.

Словил беду, никак не могу корректно прочитать ответ от сервера = приходит заголовок и текст в неизвестной кодировке. При попытке использования qUncompress - прога зависает. Пробовал распаковать с помощью zlib - ничего не меняется. Соединяюсь сервером Tomcat.

Помогите, пожалуйста. Уже нервы сдают.

Код
C++ (Qt)
"HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml;charset=Windows-1251
Transfer-Encoding: chunked
Date: Mon, 08 Aug 2011 07:46:30 GMT
Server: Apache (Unix)
 
a
?
"
153
mRNr?0u&??' ±8A?VieC«vuLa?IhB¤u??D?a|UU;now??=iwF\a?NLbU¦4eYN7o3§u}2s"


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: LisandreL от Август 08, 2011, 11:34
Transfer-Encoding: chunkedВы всех пакетов дожидаетесь?
Читаете во что? Не в QString надеюсь?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 08, 2011, 11:42
Дожидаюсь всех пакетов.
Код:
while(pClient->bytesAvailable() != 0)
Читаю в QByteArray
Код:
QByteArray incoming = pClient->readAll()


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: RedDog от Август 08, 2011, 12:28
может это в сжатом виде?
текст запроса какой?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 08, 2011, 12:34
может это в сжатом виде?
текст запроса какой?

Собственно - да. Текст сжатый, не могу его распаковать. Пробовал как уже описывал выше - qUncmpress и zlib. Удовлетворительного результат не получил.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 09, 2011, 14:18
Неужели никто не сталкивался с подобными вещами?
Никто не распаковывал данные сжатые gzip. Может я попросту неправильно пытаюсь прочитать?
Если есть примеры у кого, выложите, пожалуйста.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: RedDog от Август 09, 2011, 14:33
так попробуй распаковать через gzip а не
Цитировать
qUncmpress и zlib


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Странник от Август 09, 2011, 14:55
Неужели никто не сталкивался с подобными вещами?
Никто не распаковывал данные сжатые gzip. Может я попросту неправильно пытаюсь прочитать?
Если есть примеры у кого, выложите, пожалуйста.
по поводу 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: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 10, 2011, 07:36
Неужели никто не сталкивался с подобными вещами?
Никто не распаковывал данные сжатые gzip. Может я попросту неправильно пытаюсь прочитать?
Если есть примеры у кого, выложите, пожалуйста.
по поводу 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: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Serr500 от Август 10, 2011, 15:12
Цитировать
Transfer-Encoding: chunked
http://en.wikipedia.org/wiki/Chunked_transfer_encoding

Если кратко, то собираем все чанки в массив (конец блока чанков - нулевая длина), а затем прогоняем через gunzip.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 11, 2011, 07:11
Цитировать
Transfer-Encoding: chunked
http://en.wikipedia.org/wiki/Chunked_transfer_encoding

Если кратко, то собираем все чанки в массив (конец блока чанков - нулевая длина), а затем прогоняем через gunzip.
Можно-ли поподробней?
Вот мой код приема сообщения от сервера:
Код:
connect (pClient, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
void QSslClient::slotReadyRead()
{
    try
    {
        QByteArray incoming;
        while(pClient->bytesAvailable() != 0)
        {
            incoming = pClient->readAll();
            //Записываем ответ в глобальную переменную
            temp += incoming;//QByteArray temp
        }
    }
    catch(exception ex)
    {
        qDebug() << "###" << ex.what();
    }
}
При чем, если я помещаю всю информацию в текстовый файл - возникает множество непечатных символов. Их видно в текстовом файле, т.к. редактор не может верно определить кодировку.
Возникает вопрос: может быть с ответом приходит какой-то мусор? И его нужно фильтровать?
Файл с ответом во вложении.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Serr500 от Август 11, 2011, 08:31
Цитировать
Можно-ли поподробней?
Что там подробней? И так всё ясно. Ответ сервера закодирован два раза: вначале он пожат gzip'ом, а затем разбит на части. Соответственно, сначала необходимо собрать части воедино, а затем выполнить распаковку. Код писать лень, приведу только алгоритм.

1. Ищем конец заголовка (два символа новой строки)
2. Считываем шестнадцатиричную длину чанка, находящуюся в отдельной строке. Если длина равна нулю, переходим к шагу 5.
3. Считываем в буфер число символов, полученных на предыдущем шаге.
4. Возвращаемся к шагу 2.
5. Распаковываем содержимое буфера.

Цитировать
При чем, если я помещаю всю информацию в текстовый файл - возникает множество непечатных символов. Их видно в текстовом файле, т.к. редактор не может верно определить кодировку.
Возникает вопрос: может быть с ответом приходит какой-то мусор? И его нужно фильтровать?
Естественно, что там будут непечатные символы - это архив, а не текст. Мусора там нет, только служебная информация, её нужно убрать описанным выше методом и получить поток gzip.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 11, 2011, 11:35
Цитировать
Можно-ли поподробней?
Код писать лень, приведу только алгоритм.

Ну пожалуйста :(


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: RedDog от Август 11, 2011, 12:53
А не легче в POST запросе сказать серверу, что бы данные не сжимал?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 11, 2011, 12:57
А не легче в POST запросе сказать серверу, что бы данные не сжимал?

Пробовал разные заголовки типа:
Код:
?gzip=false
и т.д. и т.п. Все равно сжимает, нехороший такой.
На самом апаче отключить не могу, т.к. не один я туда бегаю.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 11, 2011, 15:54
А не легче в POST запросе сказать серверу, что бы данные не сжимал?

Пробовал разные заголовки типа:
Код:
?gzip=false
и т.д. и т.п. Все равно сжимает, нехороший такой.
На самом апаче отключить не могу, т.к. не один я туда бегаю.
Что такое HTTP заголовок (http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%B8_HTTP)?
И описание поля Accept-Encoding (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3) необходимого для отключения сжатия.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 12, 2011, 06:51
А не легче в POST запросе сказать серверу, что бы данные не сжимал?

Пробовал разные заголовки типа:
Код:
?gzip=false
и т.д. и т.п. Все равно сжимает, нехороший такой.
На самом апаче отключить не могу, т.к. не один я туда бегаю.
Что такое HTTP заголовок (http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%B8_HTTP)?
И описание поля Accept-Encoding (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3) необходимого для отключения сжатия.
Дело в том, что в HTTP запросе я не передаю таковой параметр на сервер. И даже если его добавляю, сервер все равно жмет данные.
Единственный выход, как я понимаю - это все-таки расжимать данные.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 12, 2011, 08:41
Цитировать
Можно-ли поподробней?
1. Ищем конец заголовка (два символа новой строки)
2. Считываем шестнадцатиричную длину чанка, находящуюся в отдельной строке. Если длина равна нулю, переходим к шагу 5.
3. Считываем в буфер число символов, полученных на предыдущем шаге.
4. Возвращаемся к шагу 2.
5. Распаковываем содержимое буфера.
Попробовал по данному алгоритму принимать данные. Результат тот же - получаемые данные не расжимаются функциями. И архив получается нечитабельным.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Serr500 от Август 12, 2011, 09:23
получаемые данные не расжимаются функциями. И архив получается нечитабельным.
1) Это не архив, а gzip-поток, у него нет заголовка, поэтому он не распознаётся как архив.
2) Какими функциями не разжимаются? qUncompress? И не будет.  ;)
3) http://blog.lugru.com/2010/06/compressing-decompressing-web-gzip-stream/ (http://blog.lugru.com/2010/06/compressing-decompressing-web-gzip-stream/) - возможно, поможет. Только там код предполагает наличие заголовка, а здесь его не будет.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Странник от Август 12, 2011, 10:17
Дело в том, что в HTTP запросе я не передаю таковой параметр на сервер. И даже если его добавляю, сервер все равно жмет данные.
Единственный выход, как я понимаю - это все-таки расжимать данные.
если не передаете этот параметр - сервер все равно может сжимать данные, лучше явно запрещать. покажите запрос свой, не может же сервер так дико косячить.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 12, 2011, 10:57
А не легче в POST запросе сказать серверу, что бы данные не сжимал?

Пробовал разные заголовки типа:
Код:
?gzip=false
и т.д. и т.п. Все равно сжимает, нехороший такой.
На самом апаче отключить не могу, т.к. не один я туда бегаю.
Что такое HTTP заголовок (http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BA%D0%B8_HTTP)?
И описание поля Accept-Encoding (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3) необходимого для отключения сжатия.
Дело в том, что в HTTP запросе я не передаю таковой параметр на сервер. И даже если его добавляю, сервер все равно жмет данные.
Единственный выход, как я понимаю - это все-таки расжимать данные.
Мне так показалось, что здесь есть какое то недопонимание: HTTP запрос - часть HTTP заголовка, но не наоборот. В запросе нельзя передать поле заголовка.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 12, 2011, 11:01
Да, без текста программы не понятно, что происходит.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 12, 2011, 12:27
Код:
POST /axis2gzip_test_orders/services/WSProxyForDB?gzip=true HTTP/1.1
SOAPAction: urn:ACTION
User-Agent: USER
Host: HOST:PORT
Transfer-Encoding: chunked
Content-Type:text/xml; charset=Windows-1251

<?xml version="1.0" encoding="Windows-1251"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Header />
        <soapenv:Body>
             <CSqueryP xmlns=\"http://service/xsd\">
                 <arg0 xmlns="">{call mod_sync_GetRemoteServersDB}</arg0>
             </CSqueryP>
        </soapenv:Body>
    </soapenv:Envelope>
Вот тестовый запрос


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 12, 2011, 14:00
А текст программы, который формирует запрос и который получает ответ? Кстати в заголовке нет поля Accept-Encoding.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 12, 2011, 14:08
Запрос:
Код:
QByteArray QSslClient::ConfigureQuery()
{
    QByteArray param0 = "{call mod_sync_GetShowsList}";
    QByteArray request = "";
    QByteArray query = "";


    request += "<?xml version=\"1.0\" encoding=\"Windows-1251\"?>";
    request += "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">";
    request += "<soapenv:Header />";
    request += "<soapenv:Body><CSqueryP xmlns=\"http://service/xsd\">";
    request += "<arg0 xmlns=\"\">" + param0 + "</arg0>";
    request += "</CSqueryP></soapenv:Body></soapenv:Envelope>";

    int len = request.length();
    QString reqLen = QString::number(len, 10);

    query += "POST /Cobo/services/WSProxyForDB?gzip=true";
    query += " HTTP/1.1\r\n";
    query += "SOAPAction: \"";
    query += "urn:ACTION";
    query += "\"\r\n";
    query += "User-Agent: ";
    query += "AGENT";
    query += "\r\n";
    query += "Host: ";
    query += "HOST";
    query += ":";
    query += "PORT";
    query += "\r\n";
    query += "Accept: */*\r\nf";
    query += "Transfer-Encoding: chunked\r\n";
    query += "Content-Type:text/xml; charset=Windows-1251\r\n\r\n";
    query += reqLen + "\r\n";
    query += request;
    query += "\r\n0\r\n\r\n";

    return query;
}
Прием:
Код:
connect (pClient, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
void QSslClient::slotReadyRead()
{
    try
    {
        QByteArray incoming;
        while(pClient->bytesAvailable() != 0)
        {
            incoming = pClient->readAll();
            //Записываем ответ в глобальную переменную
            temp += incoming;//QByteArray temp
        }
    }
    catch(exception ex)
    {
        qDebug() << "###" << ex.what();
    }
}


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 13, 2011, 10:50
Так что если написать что то вроде этого, то ни чего не меняется?
Код:
    query += "User-Agent: ";
    query += "AGENT";
    query += "\r\n";
    query += "Accept-Encoding: ";
    query += "\r\n";


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Странник от Август 13, 2011, 10:53
вряд ли поможет. судя по запросу, жмет не веб-сервер:
Код:
POST /Cobo/services/WSProxyForDB?gzip=true


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 13, 2011, 11:03
вряд ли поможет. судя по запросу, жмет не веб-сервер:
Код:
POST /Cobo/services/WSProxyForDB?gzip=true
Да точно, тогда автору остается только освоить прием чанков. Из кода выше можно только сказать, что он не гарантирует того, что пришли все данные от сервера.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 06:50
Да точно, тогда автору остается только освоить прием чанков. Из кода выше можно только сказать, что он не гарантирует того, что пришли все данные от сервера.
Как это не гарантирует? На чем, извините построили такое предположение? Можно немного конкретики?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 09:28
Да точно, тогда автору остается только освоить прием чанков. Из кода выше можно только сказать, что он не гарантирует того, что пришли все данные от сервера.
Как это не гарантирует? На чем, извините построили такое предположение? Можно немного конкретики?
Имелось в виду, что вызовов slotReadyRead() может быть произвольное количество раз, в зависимости от объема данных и скорости канала. Т.е. хотел сказать, что постоянно нужно анализировать, пришли ли все данные или нужно ждать еще пакета.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 09:30
А, собственно
Код:
while(pClient->bytesAvailable() != 0)
Не достаточно?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 09:36
А, собственно
Код:
while(pClient->bytesAvailable() != 0)
Не достаточно?
Нет, сокет может быть открыт, а буфер у него пустой - обычное дело.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 10:12
Цитировать
Нет, сокет может быть открыт, а буфер у него пустой - обычное дело.
Что-то слабо верится, что люди могли выдумать настолько извращенную систему.
Ну, ладно. Раз смогли, быть таковому.
Как тогда нужно грамотно считывать данные?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 10:33
Цитировать
Нет, сокет может быть открыт, а буфер у него пустой - обычное дело.
Что-то слабо верится, что люди могли выдумать настолько извращенную систему.
Ну, ладно. Раз смогли, быть таковому.
Как тогда нужно грамотно считывать данные?
Вполне адекватная система, TCP пакеты имеют максимальный размер чуть более килобайта, естественно 100 Кб будет разбито на множество пакетов, какой то из пакетов придет вовремя, какой то задержится, да и системный буфер на чтение не безразмерный.
Serr500 хорошо описал алгоритм чтения, к тому же длина чанка всегда впереди его, можно опираться на нее, для контроля полученных данных.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 10:40
Плюс ко всему библиотека zlib позволяет читать потоковые данные, т.е. те что еще не получены до конца, если уж сильно хочется, то можно распаковывать все на лету.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 11:11
Цитировать
Вполне адекватная система, TCP пакеты имеют максимальный размер чуть более килобайта, естественно 100 Кб будет разбито на множество пакетов, какой то из пакетов придет вовремя, какой то задержится, да и системный буфер на чтение не безразмерный.
Serr500 хорошо описал алгоритм чтения, к тому же длина чанка всегда впереди его, можно опираться на нее, для контроля полученных данных.
Да, все очень хорошо описана. Данным алгоритмом, я смог получить ровно то, что у меня и было - байт в байт! Ничего не изменилось ...


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 11:18
Цитировать
Вполне адекватная система, TCP пакеты имеют максимальный размер чуть более килобайта, естественно 100 Кб будет разбито на множество пакетов, какой то из пакетов придет вовремя, какой то задержится, да и системный буфер на чтение не безразмерный.
Serr500 хорошо описал алгоритм чтения, к тому же длина чанка всегда впереди его, можно опираться на нее, для контроля полученных данных.
Да, все очень хорошо описана. Данным алгоритмом, я смог получить ровно то, что у меня и было - байт в байт! Ничего не изменилось ...
Хорошо, а где код, который разбирает полученную информацию на чанки?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 12:27
Хорошо, а где код, который разбирает полученную информацию на чанки?

Пожалуйста:
Код:
{
        bool ok;
        QByteArray headers = "HTTP/1.1";            //Начало заголовка
        QByteArray dump;
        dump = pClient->readLine();                 //Считываем строку
        if(dump.contains(headers))                  //Если сообщение = заголовок HTTP ответа
        {
            dump = pClient->readAll();              //Считываем заголовок из буфера
        }
        else
        {
            while(true)
            {
                QString temp = dump;                //Промежуточное действия, для преобразования QByteArray в qint16
                qint16 chunk = temp.toInt(&ok, 10);
                if(!(chunk == 0))                   //Если длина чанка не нулевая
                {
                    dump = pClient->readLine(chunk);//Считываем кол-во информации = длину чанка
                    compressData.append(dump);      //Записываем информацию в глобальную переменную
                    dump = pClient->readLine();     //Считываем следующую строку, содержащую длину чанка
                }
                else break;
            }
        }
}


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: LisandreL от Август 15, 2011, 13:31
Жесть какая-то.

Код
C++ (Qt)
if(dump.contains(headers))                  //Если сообщение = заголовок HTTP ответа
{
   dump = pClient->readAll();              //Считываем заголовок из буфера
}
Чего это мы заголовок-то считываем? Мы считываем заголовок, кодированные данные, возможно даже не 1 пакет. Возможно даже нецелые пакеты. Всё что есть в буфере на текущий момент.

Код
C++ (Qt)
qint16 chunk = temp.toInt(&ok, 10);
А потом это всё считанное пытаемся превратить в число. Ничего из этого, разумеется не выходит. Мы получаем ноль и выходим.

Если бы получили не 0, то удачно бы выкинули всё, что считали в дамп и начали бы читать новую строку. :D


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 13:33
Жесть какая-то.

Код
C++ (Qt)
if(dump.contains(headers))                  //Если сообщение = заголовок HTTP ответа
{
   dump = pClient->readAll();              //Считываем заголовок из буфера
}
Чего это мы заголовок-то считываем? Мы считываем заголовок, кодированные данные, возможно даже не 1 пакет. Возможно даже нецелые пакеты. Всё что есть в буфере на текущий момент.

Код
C++ (Qt)
qint16 chunk = temp.toInt(&ok, 10);
А потом это всё считанное пытаемся превратить в число. Ничего из этого, разумеется не выходит. Мы получаем ноль и выходим.

Если бы получили не 0, то удачно бы выкинули всё, что считали в дамп и начали бы читать новую строку. :D

Может поспорим?  :D

В смысле, очень интересное замечание. Поясните, пожалуйста, на конкретном примере. Как мне необходимо было поступить.

И да, обратите внимание на конструкцию if, else.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 18:58
Хорошо, а где код, который разбирает полученную информацию на чанки?

Пожалуйста:
Код:
                QString temp = dump;                //Промежуточное действия, для преобразования QByteArray в qint16
                qint16 chunk = temp.toInt(&ok, 10);
Код конечно оставляет желать лучшего, но что можно сказать:
1) Его лучше разбить на два отдельных цикла, один разбирает заголовок, второй разбирает чанки;
2) У QByteArray тоже есть toInt() (http://doc.qt.nokia.com/4.7/qbytearray.html#toInt);
3) Почему длина чанка считается по основанию 10?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: LisandreL от Август 15, 2011, 19:17
2) У QByteArray тоже есть toInt() (http://doc.qt.nokia.com/4.7/qbytearray.html#toInt);
А я что говорил, что её нет?
Только если мы считали строку "HTTP/1.1 200 OK" и дальше по readAll() у нас в дамп попадает "Content-Encoding: gzip\nContent-Type: …" то toInt не сможет привести к числу, вернёт 0, а в ok запишет false.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 19:22
2) У QByteArray тоже есть toInt() (http://doc.qt.nokia.com/4.7/qbytearray.html#toInt);
А я что говорил, что её нет?
Каждый из нас центр вселенной :)


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 19:46
Только если мы считали строку "HTTP/1.1 200 OK" и дальше по readAll() у нас в дамп попадает "Content-Encoding: gzip\nContent-Type: …" то toInt не сможет привести к числу, вернёт 0, а в ok запишет false.

1) Мы считываем сообщение заголовка - его мы никуда не преобразовываем.
2) Уже после того, как мы счиали заголовок - проводиться проверка. Если  строка не содержит ту дребедень, то пойдут уже преобразования.

И да, собственно проблема остается актуальной, информация вид не меняет. Считываю я по основанию 10 или по 16. Вид остается прежним, абсолютно не несущим информацию. Есть идеи по поводу расжимания?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 15, 2011, 19:58
И да, собственно проблема остается актуальной, информация вид не меняет. Считываю я по основанию 10 или по 16. Вид остается прежним, абсолютно не несущим информацию. Есть идеи по поводу расжимания?
Сначала бы хотелось бы взглянуть на результат выделения чанков, на примере ранее полученного ответа от сервера.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 15, 2011, 20:51
Результат собственно получается практически идентичный. Утром отпишусь, запихнув ответ в файл.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 08:25
Появилась интересная деталь:
Преобразовывая длину чанка по основанию 10
Код:
qint16 chunk = temp.toInt(&ok, 10);
Считываю информацию. Следующее преобразование возвращает ноль, но возвращает потому, что дальше идут данные, т.е. чанк считан не полностью, и в действительности далее присутствуют данные для чтения.
Однако, если я пробую преобразовать без промежуточного присваивания в QString:
Код:
QString temp = dump;
Или пытаюсь преобразовать длину чанка по основанию 16:
Код:
qint16 chunk = temp.toInt(&ok, 16);
То считывается только кусок информации, а следующий чанк считывается пустым.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: LisandreL от Август 16, 2011, 08:45
Всё равно уверен, что читаете вы неправильно. Хотя бы потому, что чанк нельзя читать при помощи readLine, так как оно прервётся на первом же '\n', но это далеко не единственный косяк, я думаю.

Добавьте вывод в лог и покажите, что залогировалось:
Цитировать
{
        bool ok;
        QByteArray headers = "HTTP/1.1";            //Начало заголовка
        QByteArray dump;
        dump = pClient->readLine();                 //Считываем строку
        qDebug() << "1:" << dump.replace('\0',"'\\0'");
        if(dump.contains(headers))                  //Если сообщение = заголовок HTTP ответа
        {
            dump = pClient->readAll();              //Считываем заголовок из буфера
            qDebug() << "2:" << dump.replace('\0',"'\\0'");
        }
        else
        {
            while(true)
            {
                QString temp = dump;                //Промежуточное действия, для преобразования QByteArray в qint16
                qint16 chunk = temp.toInt(&ok, 10);
                qDebug() << "3:" << temp << ok << chunk;
                if(!(chunk == 0))                   //Если длина чанка не нулевая
                {
                    dump = pClient->readLine(chunk);//Считываем кол-во информации = длину чанка
                    qDebug() << "4:" << chunk << dump.length() << dump;
                    compressData.append(dump);      //Записываем информацию в глобальную переменную
                    dump = pClient->readLine();     //Считываем следующую строку, содержащую длину чанка
                }
                else break;
            }
        }
}


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 08:57
Код:
1: "HTTP/1.1 200 OK
"
2: "HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml;charset=Windows-1251
Transfer-Encoding: chunked
Date: Tue, 16 Aug 2011 05:57:00 GMT
Server: Apache (Unix)

a
?'\0''\0''\0''\0''\0''\0''\0'
"
1: "153
"
3: "153
" true 153
4: 153 153 "mRNr?0u&??' ±8A?VieC«vuLa?IhB¤u??D?a|UU;now??=iwF\a?NLbU¦4eYN7o3§u}2so?%?jO

3: "GE{ x?§??"Cr?Cya4eiJOK?ed?M?>OIy?EA(ZF??-caaU6i?¬©?a<?«obuoi?E?i?
" false 0
Если преобразовывать длину чанка по основанию 16, выдает только до:
Код:
4: 153 153 "mRNr?0u&??'	±8A?VieC«vuLa?IhB¤u??D?a|UU;now??=iwF\a?NLbU¦4eYN7o3§u}2so?%?jO

Дальше false 0 :(
Ну в смысле, там еще длина чанка получается побольше. Но строка таже получается.

Возможе-ли такой расклад: в бинарном виде поступает символ конца строки.
QByteArray воспринимает его как окончание данных и попросту не выводит их в дебаг?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: LisandreL от Август 16, 2011, 10:07
QByteArray воспринимает его как окончание данных и попросту не выводит их в дебаг?
1) Прежде всего читая dump = pClient->readLine(chunk); вы теряете всё, что после случайно встетившегося там \n.

2) Сильно подозреваю, что вот тут мы теряем первый чанк:
Цитировать
2: "HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml;charset=Windows-1251
Transfer-Encoding: chunked
Date: Tue, 16 Aug 2011 05:57:00 GMT
Server: Apache (Unix)

a
?'\0''\0''\0''\0''\0''\0''\0'
"

3) Думаю, что 153 - это 0x153 = 339, т.е. тут вы читаете чанк не целиком и дальше всё сбивается. Попробуйте qint16 chunk = temp.toInt(&ok, 16);


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 10:25
Сообщение разралось:
Код:
1: "HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml;charset=Windows-1251
Transfer-Encoding: chunked
Date: Tue, 16 Aug 2011 07:24:09 GMT
Server: Apache (Unix)

a
?
2: "153
" true 339
3: 348   "mRNr?0u&??' ±8A?VieC«vuLa?IhB¤u??D?a|UU;now??=iwF\a?NLbU¦4eYN7o3§u}2so?%?jO
v¬'\0'?^¦b|nO?¶,?1?"YA>V=mFaUI{µZ??dAUv?Xv
uZwy??V??Qq9GE{ x?§??"Cr?Cya4eiJOK?ed?M?>OIy?EA(ZF??-caaU6i?¬©?a<?«obuoi?E?i?
F
 ®gQpn?=cK1?3$~+

O?I5Q??mMtOYk?k?e?[C?/??? ?E]M?q-ZO?k\?©eu4;i­uu?[?/,o,?a?wCO?oqu?eY}&uWJ?un??­v» ?'\0''\0'"
2: "
" false 0

Однако из вывода видно, что читаемая длина чанка = 339, а длина считанного сообщения = 348  ???
Что за О_о

Разобрался, все корректно считывается. Однако, если не проводить замену символов:
Код:
dump.replace('\0', "'\\0'");
Строка получается обрезанной.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 16, 2011, 11:00
Что за О_о
Думаю дело в том, что полностью игнорируются спецификация HTTP, документация Qt и советы LisandreL и мои.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 11:12
Прежде всего читая dump = pClient->readLine(chunk); вы теряете всё, что после случайно встетившегося там \n.

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


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 16, 2011, 11:35
Первое, что нужно сделать - это переписать разбор заголовка, о чем говорилось уже множество раз, без этого ни чего работать не будет.

2) Сильно подозреваю, что вот тут мы теряем первый чанк:
Цитировать
2: "HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml;charset=Windows-1251
Transfer-Encoding: chunked
Date: Tue, 16 Aug 2011 05:57:00 GMT
Server: Apache (Unix)

a
?'\0''\0''\0''\0''\0''\0''\0'
"


Код конечно оставляет желать лучшего, но что можно сказать:
1) Его лучше разбить на два отдельных цикла, один разбирает заголовок, второй разбирает чанки;

Жесть какая-то.

Код
C++ (Qt)
if(dump.contains(headers))                  //Если сообщение = заголовок HTTP ответа
{
   dump = pClient->readAll();              //Считываем заголовок из буфера
}
Чего это мы заголовок-то считываем? Мы считываем заголовок, кодированные данные, возможно даже не 1 пакет. Возможно даже нецелые пакеты. Всё что есть в буфере на текущий момент.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 12:48
Переписал код:
Код:
void QSslClient::slotReadyRead()
{
    try
    {
        bool ok;
        qint16 chunkSize = 1;                                                   //16-тиричный размер чанка
        QString tempDump;                                                       //Вспомогательная переменная для конвертирования размера чанка
        QByteArray dump;                                                        //Переменая для чтения данных
        dump = pClient->readLine();                                             //Считываем первую строку
        if(dump.contains(START_HTTP))                                           //Если строка = начало HTTP заголовка
        {
            while(!(dump.contains(END_HTTP)))                                   //Пока не конец HTTP запроса
            {
                dump = pClient->readLine();                                     //Считываем данные
            }
            dump = pClient->read(2);                                            //Считываем окончание HTTP заголовка - 2 символа новой строки
        }
        else
        {
            tempDump = dump;                                                    //Вспомогательная операция
            chunkSize = tempDump.toInt(&ok, 16);                                //Приводим считанное значение к 16-тиричному значению длины чанка
            qDebug() << chunkSize;
            while(chunkSize != 0)                                               //Пока не считан нулевой чанк
            {
                dump = pClient->read(chunkSize);
                qDebug() << dump.replace('\0', "'\\0'");
                dump = pClient->read(2);                                        //Считываем окончание чанка
                dump = pClient->readLine();                                     //Считываем новый размер чанка
                tempDump = dump;
                chunkSize = tempDump.toInt(&ok, 16);                            //Приводим считанное значение к 16-тиричному значению длины чанка
                qDebug() << chunkSize;
            }
        }
    }
    catch(exception ex)
    {
        qDebug() << "###";
        qDebug() << ex.what();
    }
}

1. Сразу оговорюсь, в QString запихиваю значение чанка, только потому, что с новой строкой читается символ перевода строки. Что приводит к некорректному преобразованию через QByteArray::toInt();
2. Что из себя представляет вывод:
        1: Считаный размер чанка в QString
        2: Размер чанка приведенный к qint16
        3: Сам чанк

Вот получаемый вывод:
Код:
1: "a
"
2: 10
3: "?'\0''\0''\0''\0''\0''\0''\0'"
1: "153
"
2: 339
3: "mRNr?0u&??' ±8A?VieC«vuLa?IhB¤u??D?a|UU;now??=iwF\a?NLbU¦4eYN7o3§u}2so?%?jO
v¬'\0'?^¦b|nO?¶,?1?"YA>V=mFaUI{µZ??dAUv?Xv
uZwy??V??Qq9GE{ x?§??"Cr?Cya4eiJOK?ed?M?>OIy?EA(ZF??-caaU6i?¬©?a<?«obuoi?E?i?
F
 ®gQpn?=cK1?3$~+

O?I5Q??mMtOYk?k?e?[C?/??? ?E]M?q-ZO?k\?©eu4;i­uu?[?/,o,?a?wCO?oqu?eY}&uWJ?un??­v» ?'\0''\0'"
1: "0
"
2: 0

И да, некоторые символы при копировании из окна дебага сюда - пропадают.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 16, 2011, 13:07
QString::toInt() - по идее возвращает int.
Что бы не было проблем с QByteArray::toInt(), можно обрезать последние два символа.
Цикл while(chunkSize != 0)  можно сделать бесконечным while(true) - а выходить внутри цикла по break, что позволит не дублировать код.
И если результат разбора чанков визуально совпадает с тем что в ответе сервера, то можно попробовать распаковать, в гугле есть примеры этого.


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 16, 2011, 14:22
Что-то очень печальные примеры в гугле, вернее толковых там вобще найти не могу  ???
У кого-нибудь был опыт общения с zlib?


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: DmP от Август 16, 2011, 14:55
Тут (http://stackoverflow.com/questions/5741657/error-decompressing-gzip-data-using-qt) есть вариант, а так же можно посмотреть в исходниках Qt - ф-ция QHttpNetworkReplyPrivate::gunzipBodyPartially().


Название: Re: QSslSocket. Неизвестная кодировка в ответе от сервера.
Отправлено: Даниил от Август 17, 2011, 08:34
Спасибо, большое DmP!
Спасибо, большое LisandreL!
Спасибо, большое Serr500!

Первый вариант, с легкостью разжал информацию.
Еще раз спасибо, за помощь.

Тему можно закрывать.