6

I have a client/server system that performs communication using XML transferred using HTTP requests and responses with the client using Perl's LWP and the server running Perl's CGI.pm through Apache. In addition the stream is encrypted using SSL with certificates for both the server and all clients.

This system works well, except that periodically the client needs to send really large amounts of data. An obvious solution would be to compress the data on the client side, send it over, and decompress it on the server. Rather than implement this myself, I was hoping to use Apache's mod_deflate's "Input Decompression" as described here.

The description warns:

If you evaluate the request body yourself, don't trust the Content-Length header! The Content-Length header reflects the length of the incoming data from the client and not the byte count of the decompressed data stream.

So if I provide a Content-Length value which matches the compressed data size, the data is truncated. This is because mod_deflate decompresses the stream, but CGI.pm only reads to the Content-Length limit.

Alternatively, if I try to outsmart it and override the Content-Length header with the decompressed data size, LWP complains and resets the value to the compressed length, leaving me with the same problem.

Finally, I attempted to hack the part of LWP which does the correction. The original code is:

    # 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');
    }

And I changed the push line to:

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

Unfortunately this causes some problem where content (truncated or not) doesn't even get to my CGI script.

Has anyone made this work? I found this which does compression on a file before uploading, but not compressing a generic request.

4

3 回答 3

1

我认为您不能像那样更改 Content-Length 。它会使 Apache 感到困惑,因为 mod_deflate 不知道要读取多少压缩数据。让客户端添加一个 X-Uncompressed-Length 标头,然后使用使用 X-Uncompressed-Length(如果存在)而不是 Content-Length 的修改版本的 CGI.pm 怎么样?(实际上,您可能不需要修改 CGI.pm。只需$ENV{'CONTENT_LENGTH'}在初始化 CGI 对象或调用任何 CGI 函数之前设置为适当的值即可。)

或者,使用一个较低级别的模块,该模块使用 bucket brigade 来判断要读取多少数据。

于 2008-09-26T07:06:41.353 回答
1

尽管您说您不想自己进行压缩,但是有很多 perl 模块可以为您完成这两个方面,例如Compress::Zlib 。

我有一个作弊器(公司的 .net 部分),我将 XML 作为一个单独的参数传递到其中,然后可以像处理字符串一样处理它,而不是用 SOAP 之类的东西来处理它。

于 2008-09-26T13:21:07.107 回答
-1

我不确定我是否按照你想要的方式关注你,但我有一个自定义的 get/post 模块,我用它来做一些非标准的事情。下面的代码将读取通过邮寄或 STDIN 发送的任何内容。

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

不要使用 $ENV 的值,而是使用你的值。我希望这会有所帮助,如果没有,我很抱歉。

于 2008-09-26T01:35:21.617 回答