如何使用 Perl 为 HTTP 请求发送不正确的 Content-Length header?
How can I send an incorrect Content-Length header for an HTTP request using Perl?
我正在尝试调试在解析 Plack::Request 时服务器日志中出现的奇怪警告。在某些情况下,损坏的 UserAgent 会发送一个看起来像“6375, 6375”的 Content-Length header,这显然是错误的。
要正确解决此问题,我需要能够重现警告。我想将其包含在单元测试中,以便我可以确保警告消失后不会出现倒退。但是,我在使用 Perl 时遇到了麻烦。我知道这可以使用 netcat
和 socat
来完成,但我不希望单元测试必须依赖于安装其他二进制文件。
这是我试过的方法:
#!/usr/bin/env perl
use strict;
use warnings;
use JSON::XS qw( encode_json );
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->add_handler(
request_prepare => sub {
my ( $req, $ua, $h ) = @_;
$req->headers->header( 'Content-Length' => 9999 );
return;
}
);
my $json = encode_json( { foo => 'bar' } );
$mech->post(
'http://example.com'/url,
'Content-Length' => 999,
Content => $json
);
输出为:
Content-Length header value was wrong, fixed at /opt/perl5.16.3/lib/site_perl/5.16.3/LWP/Protocol/http.pm line 260.
200
这对我来说太有帮助了。 :)
如果我使用HTTP::Request and LWP::UserAgent,结果是一样的。
所以,我尝试了 HTTP::Tiny。
#!/usr/bin/env perl
use strict;
use warnings;
use DDP;
use HTTP::Tiny;
use JSON::XS qw( encode_json );
my $http = HTTP::Tiny->new;
my $json = encode_json( { foo => 'bar' } );
my $response = $http->request(
'POST',
'http://example.com'/url',
{ headers => { 'Content-Length' => 999, },
content => $json,
}
);
p $response;
输出为:
{ content => "Content-Length missmatch (got: 13 expected: 999)
",
headers => {
content
-length => 49,
content-type => "text/plain",
},
reason => "Internal Exception",
status => 599,
success => "",
url => "http://example.com'/url",
}
再一次,太有帮助了。在这一点上,我可以使用一些建议。
似乎更高级别 API 正在修复您的错误;这是一个使用原始套接字来克服这个问题的例子;
#!/usr/bin/env perl
use strict 'vars';
use warnings;
use Socket;
# initialize host and port
my $host = 'www.example.com';
my $port = 80;
# contact the server
open_tcp(F, $host, $port)
or die 'Could not connect to server';
# Send request data
while ( my $request = <DATA> ) {
print F $request;
}
# Get Response
while ( my $response = <F> ) {
print "Response:> $response";
}
close(F);
# TCP Helper
sub open_tcp
{
# get parameters
my ($FS, $dest, $port) = @_;
my $proto = getprotobyname('tcp');
socket($FS, PF_INET, SOCK_STREAM, $proto);
my $sin = sockaddr_in($port,inet_aton($dest));
connect($FS,$sin);
my $old_fh = select($FS);
$| = 1; # don't buffer output
select($old_fh);
}
__DATA__
GET / HTTP/1.1
Host: example.com
Content-Length: 999
-END-
我正在尝试调试在解析 Plack::Request 时服务器日志中出现的奇怪警告。在某些情况下,损坏的 UserAgent 会发送一个看起来像“6375, 6375”的 Content-Length header,这显然是错误的。
要正确解决此问题,我需要能够重现警告。我想将其包含在单元测试中,以便我可以确保警告消失后不会出现倒退。但是,我在使用 Perl 时遇到了麻烦。我知道这可以使用 netcat
和 socat
来完成,但我不希望单元测试必须依赖于安装其他二进制文件。
这是我试过的方法:
#!/usr/bin/env perl
use strict;
use warnings;
use JSON::XS qw( encode_json );
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->add_handler(
request_prepare => sub {
my ( $req, $ua, $h ) = @_;
$req->headers->header( 'Content-Length' => 9999 );
return;
}
);
my $json = encode_json( { foo => 'bar' } );
$mech->post(
'http://example.com'/url,
'Content-Length' => 999,
Content => $json
);
输出为:
Content-Length header value was wrong, fixed at /opt/perl5.16.3/lib/site_perl/5.16.3/LWP/Protocol/http.pm line 260.
200
这对我来说太有帮助了。 :)
如果我使用HTTP::Request and LWP::UserAgent,结果是一样的。
所以,我尝试了 HTTP::Tiny。
#!/usr/bin/env perl
use strict;
use warnings;
use DDP;
use HTTP::Tiny;
use JSON::XS qw( encode_json );
my $http = HTTP::Tiny->new;
my $json = encode_json( { foo => 'bar' } );
my $response = $http->request(
'POST',
'http://example.com'/url',
{ headers => { 'Content-Length' => 999, },
content => $json,
}
);
p $response;
输出为:
{ content => "Content-Length missmatch (got: 13 expected: 999)
",
headers => {
content
-length => 49,
content-type => "text/plain",
},
reason => "Internal Exception",
status => 599,
success => "",
url => "http://example.com'/url",
}
再一次,太有帮助了。在这一点上,我可以使用一些建议。
似乎更高级别 API 正在修复您的错误;这是一个使用原始套接字来克服这个问题的例子;
#!/usr/bin/env perl
use strict 'vars';
use warnings;
use Socket;
# initialize host and port
my $host = 'www.example.com';
my $port = 80;
# contact the server
open_tcp(F, $host, $port)
or die 'Could not connect to server';
# Send request data
while ( my $request = <DATA> ) {
print F $request;
}
# Get Response
while ( my $response = <F> ) {
print "Response:> $response";
}
close(F);
# TCP Helper
sub open_tcp
{
# get parameters
my ($FS, $dest, $port) = @_;
my $proto = getprotobyname('tcp');
socket($FS, PF_INET, SOCK_STREAM, $proto);
my $sin = sockaddr_in($port,inet_aton($dest));
connect($FS,$sin);
my $old_fh = select($FS);
$| = 1; # don't buffer output
select($old_fh);
}
__DATA__
GET / HTTP/1.1
Host: example.com
Content-Length: 999
-END-