gzip decompression, browser (delphi)

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by ErrorNeo, 21 Mar 2010.

  1. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    вопрос:

    есть html страница... скажем zalil.ru (для примера)
    ответ от сервера при её запросе выглядит так:
    Code:
    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:[email protected]">Реклама</a>
    
    </td>
    </tr>
    </table>
    
    
    <div style="position:absolute;bottom:6;right:10;">
    <[email protected] 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 - выглядит она примерно так
    Code:
    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)
    Code:
    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
     
    #1 ErrorNeo, 21 Mar 2010
    Last edited: 21 Mar 2010
    3 people like this.
  2. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Пробуй передавать на вход своей функции не переменную типа String, а какую-нибудь переменную типа TMemoryStream, так как String не сможет сохранить в себе все символы, которые передает тебе сервер.
     
  3. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    так... окей.
    Начало блока gzip - пара байт: 0x1f,0x8b (так подсказал RFC 1952)
    длинна блока... наверное 6da (или любая другая хекс-цифра, которая идет перед шифроблоком и вероятно обозначает его длинну)

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

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

    __mad Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    100
    Likes Received:
    38
    Reputations:
    7
    http://en.wikipedia.org/wiki/Chunked_transfer_encoding

    то есть

    Code:
    a
    <тут A символов>
    6da
    <тут 6da символов>
    0
    
    объединяешь в

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

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    cpc конечно, но все равно выдает ту же ошибку.
    Дело в том, что основные "тесты" я провожу, конечно же, не на паге zalil.ru.
    Та пага, где я тестюсь идет не chunked а единым блоком...(
    и увы преобразовать её (как и любую другую, не-chunked) из gzip в обычный текст обозначенный выше ф-цией не получается (почему именно - фиг его знает. "data error")

    было бы супер, если бы гашелся кто-то, ко когда-нибудь реализовывал комбинацию delphi+windows_sockets+gzip
     
    #5 ErrorNeo, 21 Mar 2010
    Last edited: 21 Mar 2010
  6. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Мож баг в распаковщике? Ты попробуй полученный код распаковать в php
    и если удастся, нормально, значит баг в модуле
     
    1 person likes this.
  7. noneim

    noneim New Member

    Joined:
    28 Nov 2007
    Messages:
    4
    Likes Received:
    0
    Reputations:
    0
    Распаковка gzip (взято отсюда - http://www.rsdn.ru/forum/winapi/2171857.flat.aspx):
    Code:
    
    
    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 символы?
     
  8. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    я тоже нашел ф-ции для Си, и даже не для файлов, а для строк. Но все же, наверное, в названии темы не зря написано слово "Delphi" :)
    Знаешь ли, не всегда просто перевести код (который не понимаешь) с одного языка, который плохо понимаешь на другой, который, пусть даже, и знаешь более менее неплохо.
     
    #8 ErrorNeo, 29 Mar 2010
    Last edited: 29 Mar 2010
  9. s0l_ir0n

    s0l_ir0n Active Member

    Joined:
    14 Mar 2009
    Messages:
    399
    Likes Received:
    144
    Reputations:
    18
    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
     
  10. maestro-ant

    maestro-ant New Member

    Joined:
    7 Jan 2007
    Messages:
    26
    Likes Received:
    4
    Reputations:
    6
    можно гору обойти:
    в заголовок-запроса напиши так чтоб сервер не паковал данные
     
  11. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Нет, ну ты в реале уникальный человек!!! Ему нужно именно расшифровать запакованные данные, а не получить чистый текст от сервака.
     
  12. ErrorNeo

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    я это нашел и сам. только приспособить это к пакованым http запросам чета не получается...=\
    может конечно мало *лся... там есть какие-то ф-ции для работы с "потоковыми данными" итд. Хотя.. все же хотелось бы по возможности увидеть готовый пример.

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

    Meecript_ Banned

    Joined:
    29 Oct 2008
    Messages:
    194
    Likes Received:
    62
    Reputations:
    32
    ErrorNeo, юзай либкурл и будет тебе счастье ;)
     
  14. maestro-ant

    maestro-ant New Member

    Joined:
    7 Jan 2007
    Messages:
    26
    Likes Received:
    4
    Reputations:
    6
    Chrome~
    попрошу без оскорблений.

    ErrorNeo
    Мой совет вполне дельный. Разве тебе критично-нужно чтоб трафик был упакованный? Если нет, то в заголовке запроса, который отсылаешь серверу нужно выкинуть строчку Accept-encoding gzip. И все! упаковка данных происходить не будет.
    Я так делал когда писал "подмену выдачи". gzip-тупо не нужен мне был. Она нужна для экономии трафика.
     
    #14 maestro-ant, 2 Apr 2010
    Last edited: 2 Apr 2010
  15. Meecript_

    Meecript_ Banned

    Joined:
    29 Oct 2008
    Messages:
    194
    Likes Received:
    62
    Reputations:
    32
    Ему это как раз и нужно )
     
  16. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Я вас не оскорблял.

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

    ErrorNeo Elder - Старейшина

    Joined:
    2 May 2009
    Messages:
    923
    Likes Received:
    838
    Reputations:
    402
    да, знаю, что либкурл поможет(((
    но в данном случае доделаю всё и без коспрессии, а дальше...
    если еще 1 приложение придется писать такое - а полюбому придется - буду уже юзать.... либкурл :'(
    (прогонять полтора террабафта траффика вообще без компрессии это все излишне же сурово, даже для меня)

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

    обломно.
     
  18. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Пробовал TIdCompressorZLib прикрутить? Что-то мне кажется что не пробовал

    Кстати реальный пример того что библиотеки типа инди не хуже винсок. Гзип уменьшает трафф на порядка 70%, вот и посчитайте сколько страниц можно получить в инди и в винсок за промежуток времени
     
    #18 GhostOnline, 5 Apr 2010
    Last edited: 5 Apr 2010
  19. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    ErrorNeo если еспользуется Indy 9(Delphi 7), то багов в ней куча и gzip там попросту не работает. Для этого нужно скачать заплатки этой версии(там вполть до Classes) :)

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

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

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    Блин, я туплю, но один фик посмотреть те сорцы можно и вытащить для себя то что нужно:)