Russian Qt Forum
Ноябрь 24, 2024, 00:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4]   Вниз
  Печать  
Автор Тема: QSslSocket. Неизвестная кодировка в ответе от сервера.  (Прочитано 27418 раз)
Даниил
Гость
« Ответ #45 : Август 15, 2011, 20:51 »

Результат собственно получается практически идентичный. Утром отпишусь, запихнув ответ в файл.
Записан
Даниил
Гость
« Ответ #46 : Август 16, 2011, 08:25 »

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

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #47 : Август 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;
            }
        }
}
Записан
Даниил
Гость
« Ответ #48 : Август 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 воспринимает его как окончание данных и попросту не выводит их в дебаг?
« Последнее редактирование: Август 16, 2011, 09:07 от Даниил » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #49 : Август 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);
Записан
Даниил
Гость
« Ответ #50 : Август 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'");
Строка получается обрезанной.
« Последнее редактирование: Август 16, 2011, 10:52 от Даниил » Записан
DmP
Гость
« Ответ #51 : Август 16, 2011, 11:00 »

Что за О_о
Думаю дело в том, что полностью игнорируются спецификация HTTP, документация Qt и советы LisandreL и мои.
Записан
Даниил
Гость
« Ответ #52 : Август 16, 2011, 11:12 »

Прежде всего читая dump = pClient->readLine(chunk); вы теряете всё, что после случайно встетившегося там \n.

Тогда как можно, гарантированно безопасно считать длину чанка?
Записан
DmP
Гость
« Ответ #53 : Август 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 пакет. Возможно даже нецелые пакеты. Всё что есть в буфере на текущий момент.
« Последнее редактирование: Август 16, 2011, 11:38 от DmP » Записан
Даниил
Гость
« Ответ #54 : Август 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

И да, некоторые символы при копировании из окна дебага сюда - пропадают.
« Последнее редактирование: Август 16, 2011, 13:05 от Даниил » Записан
DmP
Гость
« Ответ #55 : Август 16, 2011, 13:07 »

QString::toInt() - по идее возвращает int.
Что бы не было проблем с QByteArray::toInt(), можно обрезать последние два символа.
Цикл while(chunkSize != 0)  можно сделать бесконечным while(true) - а выходить внутри цикла по break, что позволит не дублировать код.
И если результат разбора чанков визуально совпадает с тем что в ответе сервера, то можно попробовать распаковать, в гугле есть примеры этого.
« Последнее редактирование: Август 16, 2011, 13:08 от DmP » Записан
Даниил
Гость
« Ответ #56 : Август 16, 2011, 14:22 »

Что-то очень печальные примеры в гугле, вернее толковых там вобще найти не могу  Непонимающий
У кого-нибудь был опыт общения с zlib?
Записан
DmP
Гость
« Ответ #57 : Август 16, 2011, 14:55 »

Тут есть вариант, а так же можно посмотреть в исходниках Qt - ф-ция QHttpNetworkReplyPrivate::gunzipBodyPartially().
Записан
Даниил
Гость
« Ответ #58 : Август 17, 2011, 08:34 »

Спасибо, большое DmP!
Спасибо, большое LisandreL!
Спасибо, большое Serr500!

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

Тему можно закрывать.
Записан
Страниц: 1 2 3 [4]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.173 секунд. Запросов: 23.