Сжатие HTTP-запроса с LWP, Apache и mod_deflate - PullRequest
6 голосов
/ 26 сентября 2008

У меня есть система клиент / сервер, которая осуществляет связь с использованием XML, передаваемого с использованием HTTP-запросов и ответов, с клиентом с использованием LWP Perl и сервером, на котором выполняется CGI.pm в Perl через Apache. Кроме того, поток шифруется с использованием SSL с сертификатами как для сервера, так и для всех клиентов.

Эта система работает хорошо, за исключением того, что периодически клиенту необходимо отправлять действительно большие объемы данных. Очевидным решением будет сжатие данных на стороне клиента, их передача и распаковка на сервере. Вместо того, чтобы реализовывать это самостоятельно, я надеялся использовать «декомпрессию ввода» Apache mod_deflate, как описано здесь .

Описание предупреждает:

Если вы оцениваете тело запроса самостоятельно, не доверяйте заголовку Content-Length! Заголовок Content-Length отражает длину входящих данных от клиента, а не количество байтов потока распакованных данных.

Так что, если я предоставлю значение Content-Length, соответствующее размеру сжатых данных, данные будут обрезаны. Это происходит потому, что mod_deflate распаковывает поток, но CGI.pm читает только до предела длины содержимого.

В качестве альтернативы, если я попытаюсь перехитрить его и переопределить заголовок Content-Length с размером распакованных данных, LWP пожалуется и сбрасывает значение до сжатой длины, оставляя меня с той же проблемой.

Наконец, я попытался взломать часть LWP, которая делает исправление. Оригинальный код:

    # Set (or override) Content-Length header
    my $clen = $request_headers->header('Content-Length');
    if (defined($$content_ref) && length($$content_ref)) {
        $has_content = length($$content_ref);
        if (!defined($clen) || $clen ne $has_content) {
            if (defined $clen) {
                warn "Content-Length header value was wrong, fixed";
                hlist_remove(\@h, 'Content-Length');
            }
            push(@h, 'Content-Length' => $has_content);
        }
    }
    elsif ($clen) {
        warn "Content-Length set when there is no content, fixed";
        hlist_remove(\@h, 'Content-Length');
    }

И я изменил линию на:

  push(@h, 'Content-Length' => $clen);

К сожалению, это вызывает некоторые проблемы, когда содержимое (усеченное или нет) даже не попадает в мой CGI-скрипт.

Кто-нибудь сделал эту работу? Я нашел this , который выполняет сжатие файла перед загрузкой, но не сжимает общий запрос.

Ответы [ 3 ]

1 голос
/ 26 сентября 2008

Не думаю, что вы можете изменить Content-Length таким образом. Это может запутать Apache, потому что mod_deflate не будет знать, сколько сжатых данных нужно прочитать. Как насчет того, чтобы клиент добавил заголовок X-Uncompressed-Length, а затем использовал измененную версию CGI.pm, которая использует X-Uncompressed-Length (если присутствует) вместо Content-Length? (На самом деле, вам, вероятно, не нужно изменять CGI.pm. Просто установите $ENV{'CONTENT_LENGTH'} на соответствующее значение перед инициализацией объекта CGI или вызовом любых функций CGI.)

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

1 голос
/ 26 сентября 2008

Несмотря на то, что вы сказали, что не хотите выполнять сжатие самостоятельно, существует множество модулей Perl, которые будут выполнять обе функции, например, Compress :: Zlib .

У меня есть чит (с .net-частью компании), где я передаю XML в виде отдельного параметра, размещенного в нем, а затем могу обрабатывать его, как если бы это была строка, а не копаться в SOAP-подобных вещах.

0 голосов
/ 26 сентября 2008

Я не уверен, что слежу за вами с тем, что вы хотите, но у меня есть специальный модуль get / post, который я использую для выполнения нестандартных задач Код ниже будет читать все, что отправлено по почте или STDIN.

read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});

Вместо использования значения $ ENV используйте ваше. Я надеюсь, что это помогает, и извините, если это не так.

...