使用LWP,Apache和mod_deflate压缩HTTP请求
我有一个客户机/服务器系统,该系统使用通过HTTP请求和响应传输的XML与使用Perl的LWP的客户机以及通过Apache运行Perl的CGI.pm的服务器进行通信。此外,使用SSL对服务器和所有客户端使用证书对流进行加密。
该系统运行良好,只是客户端需要定期发送大量数据。一个显而易见的解决方案是在客户端上压缩数据,将其发送出去,然后在服务器上对其进行解压缩。我希望自己使用此处描述的Apache的mod_deflate的"输入解压缩",而不是自己实现。
描述警告:
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.
因此,如果我提供与压缩数据大小匹配的Content-Length值,则数据将被截断。这是因为mod_deflate对流进行解压缩,但是CGI.pm仅读取Content-Length限制。
另外,如果我尝试使其智能化并用解压缩的数据大小覆盖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脚本。
有人做过这项工作吗?我发现它可以在上传之前对文件进行压缩,但不能压缩通用请求。
解决方案
我不确定是否跟随需求,但是我有一个自定义的获取/发布模块,可以用来做一些非标准的事情。以下代码将读取通过邮寄或者STDIN发送的所有内容。
read(STDIN, $query_string, $ENV{'CONTENT_LENGTH'});
不要使用$ ENV的值,而要使用值。我希望这会有所帮助,如果不能,对不起。
我认为我们不能像这样更改Content-Length。这会使Apache感到困惑,因为mod_deflate不知道要读取多少压缩数据。如何让客户端添加X-Uncompressed-Length标头,然后使用CGI.pm的修改版本,该版本使用X-Uncompressed-Length(如果存在)而不是Content-Length? (实际上,我们可能不需要修改CGI.pm。只需在初始化CGI对象或者调用任何CGI函数之前将$ ENV {'CONTENT_LENGTH'}`设置为适当的值。)
或者,使用一个较低级别的模块,该模块使用存储桶来告诉我们要读取多少数据。
尽管我们说自己不想自己进行压缩,但是有很多perl模块可以为我们完成压缩工作,例如Compress :: Zlib。
我有一个作弊(公司的.net部分),在其中我将XML作为单独的参数传递出来,然后可以像对待字符串一样处理它,而不是喜欢SOAP之类的东西。