Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   gzip decompression, browser (delphi) (https://forum.antichat.xyz/showthread.php?t=189024)

ErrorNeo 21.03.2010 20:39

gzip decompression, browser (delphi)
 
вопрос:

есть html страница... скажем zalil.ru (для примера)
ответ от сервера при её запросе выглядит так:
Код:

HTTP/1.1 200 OK
Server: nginx/0.3.17
Date: Sun, 21 Mar 2010 16:22:39 GMT
Content-Type: text/html; charset=windows-1251
Transfer-Encoding: chunked
Connection: keep-alive

e90
<html>

<head>
  <title>Хранение файла, бесплатно закачать и скачать</title>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" media="all" href="/style/default.css" />
</head>
<body>


<table id="container">

<tr>
<td id="content">
<div style="position:absolute; top:20px; right:20px; text-align:right;">

<form name="search" action="/page/search" method="get">
<input name="name" type="text" value="Поиск" style="width:200px;" onfocus="this.value=''" onblur="if(this.value=='')this.value='Поиск'">
</form>
<br>

Обладатели Flash Player могут <a href="/page/test">протестировать</a> новый аплоадер.<br><br>
В некоторых подсетях плохая скорость соединения.<br> Ведутся переговоры с хостером, надеемся разрешить эту проблему.
</div>

<div id="center">


<form action="/upload/" name="sendform" enctype="multipart/form-data" method="post" id="sendform" onSubmit="sending()">

<input type="file" name="file" size="53" onFocus="choice()" onclick="choice()">
<input type="submit" name="submit" value="&nbsp;&nbsp;Send&nbsp;&nbsp;" id="submit">
</form>

<p>Сервис позволяет разместить файл размером не более 50 Мб.<br>
Файл будет удален через 1 месяц после последнего скачивания.</p>


</div>


<script language="JavaScript">

var sendform;
var flag;

setTimeout(function() {
sendform=document.getElementById("sendform");
flag=1;
sendform.submit.disabled=true;
sendform.submit.value='  Send  ';

        }, 200);


function choice()
{
if(flag==1)
sendform.submit.disabled=false;
}

function sending()
{
sendform.submit.disabled=true;
sendform.submit.value="Sending";
flag=0;
}
</script>



</td>
</tr>
<tr>
<td id="copyright">


<!-- # ECTO*COUNTER-->
<script language="javascript">
document.write('<img s'+'rc="http://support.ecto.ru/counter.php'+
'?i=2&r='+escape(document.referrer)+
'" style="border:0;"/>');
</script>
<noscript>
<img src="http://support.ecto.ru/counter.php?i=2" border="0"/>
</noscript>
<!-- # ECTO*COUNTER-->


<span>&copy;2010 <a href="http://fhn.ru">fhn*createam</a></span>
<a href="/page/">О&nbsp;проекте</a>
<a href="mailto:ad@zalil.ru">Реклама</a>

</td>
</tr>
</table>


<div style="position:absolute;bottom:6;right:10;">
<!--Rating@Mail.ru COUNTEr--><script language="JavaScript" type="text/javascript"><!--
d=document;var a='';a+=';r='+escape(d.referrer)
js=10//--></script><script language="JavaScript1.1" type="text/javascript"><!--
a+=';j='+navigator.javaEnabled()
js=11//--></script><script language="JavaScript1.2" type="text/javascript"><!--
s=screen;a+=';s='+s.width+'*'+s.height
a+=';d='+(s.colorDepth?s.colorDepth:s.pixelDepth)
js=12//--></script><script language="JavaScript1.3" type="text/javascript"><!--
js=13//--></script><script language="JavaScript" type="text/javascript"><!--
d.write('<a href="http://top.mail.ru/jump?from=956201"'+
' target=_top><img src="http://d7.c9.be.a0.top.list.ru/counter'+
'?id=956201;t=84;js='+js+a+';rand='+Math.random()+
'" alt="Рейтинг@Mail.ru"'+' border=0 height=18 width=88/><\/a>')
if(11<js)d.write('<'+'!-- ')//--></script><noscript><a
target=_top href="http://top.mail.ru/jump?from=956201"><img
src="http://d7.c9.be.a0.top.list.ru/counter?js=na;id=956201;t=84"
border=0 height=18 width=88
alt="Рейтинг@Mail.ru"/></a></noscript><script language="JavaScript" type="text/javascript"><!--
if(11<js)d.write('--'+'>')//--></script><!--/COUNTER-->


</div>








<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2283330-1";
urchinTracker();
</script>






</body>

</html>
0

есть та же самая страница, запрошенная с изпользованием gzip - выглядит она примерно так
Код:

HTTP/1.1 200 OK
Server: nginx/0.3.17
Date: Sun, 21 Mar 2010 16:06:59 GMT
Content-Type: text/html; charset=windows-1251
Transfer-Encoding: chunked
Connection: keep-alive
Content-Encoding: gzip

a
<тут 10 символов>
6da
<тут 24 строки с разными символами>
0

Собствено вопрос:
1. Откуда считать начало gzip тела (которое длинной 6da) - с начала строки, следующей за строкой с размером и до строки с нулем без учета символов переноса строки перед нулем?
2. как конвертнуть текст gzip обратно в нормальный?
ф-цией (из либы ZLibEx)
Код:

function DecompressString(const aString: string): string;
var
  lStr: TStringStream;
  lDS: TZDecompressionStream;
begin
  lStr := TStringStream.Create(aString);
  try
    lDS := TZDecompressionStream.Create(lStr);
    try
      SetLength(Result, lDS.Size);
      lDS.Read(Pointer(Result)^, lDS.Size);
    finally
      lDS.Free;
    end;
  finally
    lStr.Free;
  end;
end;

увы не удается - пишет "data error", при том что на вход ф-ции я подаю следующее:
reply:=copy(reply,pos('6da',reply)+3,1754); //1745 это 6da
где reply - изначально полученный мной от сервера ответ.

Прошу показать как с этим справиться конкретно на примере страницы zalil.ru, т.к. она маленькая + неизменяющаяся.
Но можно и на любой другой

ps.
вожусь с этой *ней уже часов 6.
за реальную помощь в решении вопроса преобразования gzip в обычный текст при использовании сокетов (никаких компонет, никакого инди - мне 1000-1500 потоков надо - инди убьет себя) с меня +20

Chrome~ 21.03.2010 22:14

Пробуй передавать на вход своей функции не переменную типа String, а какую-нибудь переменную типа TMemoryStream, так как String не сможет сохранить в себе все символы, которые передает тебе сервер.

ErrorNeo 21.03.2010 22:21

так... окей.
Начало блока gzip - пара байт: 0x1f,0x8b (так подсказал RFC 1952)
длинна блока... наверное 6da (или любая другая хекс-цифра, которая идет перед шифроблоком и вероятно обозначает его длинну)

тем не менее, как я не варьирую длинну блока (исходя из того, что первый символ блока - 0x1f) - все равно получаю "data error" :-(

Chrome~ - хз..
ф-ция, что я указал (найденная в гугле) вроде как работает именно с переменной string. хотя фиг его знает что тут как, если быть до конца точным

__mad 22.03.2010 00:09

http://en.wikipedia.org/wiki/Chunked_transfer_encoding

то есть

Код:

a
<тут A символов>
6da
<тут 6da символов>
0

объединяешь в

Код:

<тут A символов><тут 6da символов>
и передаешь в zlib

ErrorNeo 22.03.2010 00:48

Цитата:

Сообщение от __mad
...

cpc конечно, но все равно выдает ту же ошибку.
Дело в том, что основные "тесты" я провожу, конечно же, не на паге zalil.ru.
Та пага, где я тестюсь идет не chunked а единым блоком...(
и увы преобразовать её (как и любую другую, не-chunked) из gzip в обычный текст обозначенный выше ф-цией не получается (почему именно - фиг его знает. "data error")

было бы супер, если бы гашелся кто-то, ко когда-нибудь реализовывал комбинацию delphi+windows_sockets+gzip

slesh 22.03.2010 00:57

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

noneim 22.03.2010 16:23

Распаковка gzip (взято отсюда - http://www.rsdn.ru/forum/winapi/2171857.flat.aspx):
Код:



BOOL WINAPI DecompressFile(HANDLE hArchFile, HANDLE hPlainFile)
{
    HRESULT rc;
    IEncodingFilterFactory* pEflt=NULL;
    IDataFilter* pDF=NULL;
    BOOL bOK=TRUE;
    rc = CoCreateInstance( CLSID_StdEncodingFilterFac, NULL, CLSCTX_INPROC_SERVER, IID_IEncodingFilterFactory, (LPVOID *) &pEflt);
        if( FAILED(rc) )
        return FALSE;
    pEflt->GetDefaultFilter(_T("gzip"), _T("text"), &pDF);
    if (pDF)
    {
            BYTE in_buff[32768];
        BYTE out_buff[32768];
        DWORD rdd=0;
        DWORD wrt=0;
        LONG proc=0;
        LONG outpt=0;
        __int64 filesize=0;
        __int64 processed=0;
        GetFileSizeEx(hArchFile, (PLARGE_INTEGER)&filesize);
        while (processed<filesize)
        {
            SetFilePointerEx(hArchFile, *((PLARGE_INTEGER)&processed), NULL, FILE_BEGIN);
            ReadFile(hArchFile, in_buff, sizeof(in_buff), &rdd, NULL);
            rc=pDF->DoDecode(0, sizeof(in_buff), in_buff, sizeof(out_buff), out_buff, rdd, &proc, &outpt, 0);
            if (FAILED(rc))
            {
                bOK=FALSE;
                break;
            }
            WriteFile(hPlainFile, out_buff, outpt, &wrt, NULL);
            processed+=proc;
        }
        do
        {
            rc=pDF->DoDecode(0, sizeof(in_buff), in_buff, sizeof(out_buff), out_buff, 0, &proc, &outpt, 0);
            if (FAILED(rc))
            {
                bOK=FALSE;
                break;
            }
            WriteFile(hPlainFile, out_buff, outpt, &wrt, 0);
        }while(outpt>0);
        pDF->Release();
        pEflt->Release();
        return bOK;
    }
    pEflt->Release();
    return FALSE;
}

все работает, проверено
может учитывал лишние \r\n символы?

ErrorNeo 29.03.2010 08:09

Цитата:

Сообщение от noneim
все работает, проверено
может учитывал лишние \r\n символы?

я тоже нашел ф-ции для Си, и даже не для файлов, а для строк. Но все же, наверное, в названии темы не зря написано слово "Delphi" :)
Знаешь ли, не всегда просто перевести код (который не понимаешь) с одного языка, который плохо понимаешь на другой, который, пусть даже, и знаешь более менее неплохо.

s0l_ir0n 29.03.2010 11:02

delphi zlib 1.2.3.2009
# zlib version 1.2.3 for delphi 5, 6, 7, 8, 2005, 2006, 2007, 2009
# now supports simple gzip files
# includes zlib source code and c++ builder 6 project files (c++ builder 6 was used to compile c source into object files)

http://www.base2ti.com/zlib.htm

maestro-ant 30.03.2010 00:49

можно гору обойти:
в заголовок-запроса напиши так чтоб сервер не паковал данные

Chrome~ 30.03.2010 01:08

Цитата:

Сообщение от maestro-ant
можно гору обойти:
в заголовок-запроса напиши так чтоб сервер не паковал данные

Нет, ну ты в реале уникальный человек!!! Ему нужно именно расшифровать запакованные данные, а не получить чистый текст от сервака.

ErrorNeo 31.03.2010 09:49

Цитата:

Сообщение от s0l_ir0n
delphi zlib 1.2.3.2009
# zlib version 1.2.3 for delphi 5, 6, 7, 8, 2005, 2006, 2007, 2009
# now supports simple gzip files
# includes zlib source code and c++ builder 6 project files (c++ builder 6 was used to compile c source into object files)

http://www.base2ti.com/zlib.htm

я это нашел и сам. только приспособить это к пакованым http запросам чета не получается...=\
может конечно мало *лся... там есть какие-то ф-ции для работы с "потоковыми данными" итд. Хотя.. все же хотелось бы по возможности увидеть готовый пример.

maestro-ant - хром уже ответил. "Не паковать данные"? - я и так их(в данный момент) не пакую... потому что не умею распаковывать:( Но хотелось бы все-таки научиться, чтобы уменьшить затраты траффика => увеличить количество обрабатываемых http страниц в минуту.

M_script_ 31.03.2010 10:24

ErrorNeo, юзай либкурл и будет тебе счастье ;)

maestro-ant 02.04.2010 14:32

Chrome~
попрошу без оскорблений.

ErrorNeo
Мой совет вполне дельный. Разве тебе критично-нужно чтоб трафик был упакованный? Если нет, то в заголовке запроса, который отсылаешь серверу нужно выкинуть строчку Accept-encoding gzip. И все! упаковка данных происходить не будет.
Я так делал когда писал "подмену выдачи". gzip-тупо не нужен мне был. Она нужна для экономии трафика.

M_script_ 02.04.2010 15:03

Цитата:

Сообщение от maestro-ant
Она нужна для экономии трафика.

Ему это как раз и нужно )

Chrome~ 02.04.2010 16:10

Цитата:

Сообщение от maestro-ant
Chrome~
попрошу без оскорблений.

Я вас не оскорблял.

Тоже интересуюсь данным вопросом, раньше искал ответ, но так и не нашел.

ErrorNeo 05.04.2010 14:49

да, знаю, что либкурл поможет(((
но в данном случае доделаю всё и без коспрессии, а дальше...
если еще 1 приложение придется писать такое - а полюбому придется - буду уже юзать.... либкурл :'(
(прогонять полтора террабафта траффика вообще без компрессии это все излишне же сурово, даже для меня)

maestro-ant - да, мне критична именно экономия траффика. Без упаковки я запросы и так умею слать - да и любой дурак умеет. Не в обиду тебе.) А вот распавовывать пакованные методами дельфи - увы - далеко не каждый. Если быть точнее - то судя по этой теме вообще никто это не делал у нас при использовании вин-сок, да и... вообще хоть каким-либо методом на дельфи.

обломно.

GhostOnline 05.04.2010 20:35

Пробовал TIdCompressorZLib прикрутить? Что-то мне кажется что не пробовал

Кстати реальный пример того что библиотеки типа инди не хуже винсок. Гзип уменьшает трафф на порядка 70%, вот и посчитайте сколько страниц можно получить в инди и в винсок за промежуток времени

Jingo Bo 05.04.2010 21:48

ErrorNeo если еспользуется Indy 9(Delphi 7), то багов в ней куча и gzip там попросту не работает. Для этого нужно скачать заплатки этой версии(там вполть до Classes) :)

Вот архив :
http://slil.ru/28913262

Распаковывешь эту папку в папку сос воей прогой и все *.pas подключаем к проекту через Project Manager, перезапускаем Delphi и используем как пытались, могу поспорить в этом беда.

Jingo Bo 05.04.2010 21:51

Блин, я туплю, но один фик посмотреть те сорцы можно и вытащить для себя то что нужно:)

M_script_ 05.04.2010 23:01

Цитата:

Сообщение от GhostOnline
Кстати реальный пример того что библиотеки типа инди не хуже винсок.

А ты запусти 1000 потоков в проге, написанной на инди и сразу поймешь, чем инди хуже ;)

GhostOnline 06.04.2010 00:10

А нахрена 1000 потоков если и 300 упирается в лимит траффа?

Инди дохрена процессорного времени отбирает?

M_script_ 06.04.2010 02:07

Цитата:

Сообщение от GhostOnline
А нахрена 1000 потоков если и 300 упирается в лимит траффа?

Это от канала зависит и от размера страниц. Может и 1к потоков не весь канал забивать, примеры есть.

Цитата:

Сообщение от GhostOnline
Инди дохрена процессорного времени отбирает?

Слишком много ошибок начинает появляться при большом количестве потоков.

Jingo Bo 06.04.2010 02:29

Цитата:

Слишком много ошибок начинает появляться при большом количестве потоков.
Нет, проверял, даже при большом количестве (+ 400) разницы нет. Проблема с инди в том что много логических ошибок, у меня на 9 основные исправлены, пока не замечал. А так использовать можно:)

И кстати если при большом количестве у вас начинает в инди сыпаться мног ошибок - скорее всего плохая синхронизация потоков. Есть в инди одно узкое конечно место где все потоки сходятся, но там всё идеально сделано.(Файл IdComponent.pas, создание класса) Там речь идёт о критической секции и прикол в том что на XP(ещё где хз) при огромном количестве потоков эти критические секции(по сути системные объекты) глючат(пропускают потоки, когда главный поток блокирует), не объяснимо но факт. Может там трабла, я хз.

Jingo Bo 06.04.2010 02:30

Цитата:

Это от канала зависит и от размера страниц. Может и 1к потоков не весь канал забивать, примеры есть.
Не помню какое на XP хом эдишн стоит ограничение на использование активных TCP соединений, но не высокое.

M_script_ 06.04.2010 04:00

Цитата:

Сообщение от Jingo Bo
И кстати если при большом количестве у вас начинает в инди сыпаться мног ошибок - скорее всего плохая синхронизация потоков.

С синхронизацией все нормально. В инди проблемы в основном при использовании прокси.

Цитата:

Сообщение от Jingo Bo
Не помню какое на XP хом эдишн стоит ограничение на использование активных TCP соединений, но не высокое.

Я win2003 использую обычно )

[stranger] 07.04.2010 00:07

как плавно съехали с gzip.. :)
по сабжу: что-то GZDecompressStr не хочет работать с результатом GZCompressStr.. Data Error! В чем прикол?

nick1000 17.04.2010 20:48

Вот нашел в нете функцию позволяющую распаковывать gzip без заголовка(10 байт) и окончания (8 байт=CRC32+длинна исходного текста). На залил ру ответ без окончания.

а вообще ошибка возникала из-за того что в TZDecompressionStream используется InflateInit_ в котором по-умолчанию стоит windowBits=15, а нужно windowBits=-15 , что и указывается в InflateInit2_
(хотя сам адлер пишет что этот параметр должен быть в диапазоне 8..15).

Вот код:

Код:

function InflateInit2(var stream: TZStreamRec; windowBits: Integer): Integer;
begin
  result := InflateInit2_(stream,windowBits,ZLIB_VERSION,SizeOf(TZStreamRec));
end;


function ZDecompressCheck(code: Integer): Integer;
begin
  Result := code;

  if code < 0 then
  begin
    raise EZDecompressionError.Create(_z_errmsg[2 - code]);
  end;
end;

procedure GZDecompress(const inBuffer: Pointer; inSize: Integer;
  out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer = 0);
var
  zstream: TZStreamRec;
  delta  : Integer;
begin
  FillChar(zstream,SizeOf(TZStreamRec),0);

  delta := (inSize + 255) and not 255;

  if outEstimate = 0 then outSize := delta
  else outSize := outEstimate;

  GetMem(outBuffer,outSize);

  try
    zstream.next_in := inBuffer;
    zstream.avail_in := inSize;
    zstream.next_out := outBuffer;
    zstream.avail_out := outSize;

    ZDecompressCheck(InflateInit2(zstream, -15));

    try
      while ZDecompressCheck(inflate(zstream,Z_NO_FLUSH)) <> Z_STREAM_END do
      begin
        Inc(outSize,delta);
        ReallocMem(outBuffer,outSize);

        zstream.next_out := PAnsiChar(Integer(outBuffer) + zstream.total_out);
        zstream.avail_out := delta;
      end;
    finally
      ZDecompressCheck(inflateEnd(zstream));
    end;

    ReallocMem(outBuffer,zstream.total_out);
    outSize := zstream.total_out;
  except
    FreeMem(outBuffer);
    raise;
  end;
end;


function GZDecompressStr(const s: AnsiString): AnsiString;
var
  buffer: Pointer;
  size  : Integer;
begin
  GZDecompress(PChar(s),Length(s),buffer,size);

  SetLength(result,size);
  Move(buffer^,result[1],size);

  FreeMem(buffer);
end;


procedure TForm1.Button6Click(Sender: TObject);
var ss,s,reply:string;
begin

Здесь получаем ответ через winsocks
........
    reply:=copy(reply,pos('6da',reply),1757);
 //или по-другому. Главное чтобы в reply остался '6da' .

    s := Copy(reply, 11, Length(reply)-10);
    ss:=GZDecompressStr(s);
    Memo1.Text:=ss;
end;



Время: 23:02