Perl IO::Socket服务器和POST数据存在小问题
出于某些原因,我只能使用IO::Socket构建我的小型http服务器(而不是专用于此的其他模块) 编辑1:我编辑了我的问题,我想知道我可以放什么,而不是评论行“#last…” 这是我的剧本:Perl IO::Socket服务器和POST数据存在小问题,perl,http,serversocket,io-socket,Perl,Http,Serversocket,Io Socket,出于某些原因,我只能使用IO::Socket构建我的小型http服务器(而不是专用于此的其他模块) 编辑1:我编辑了我的问题,我想知道我可以放什么,而不是评论行“#last…” 这是我的剧本: use strict; use IO::Socket; my $server = IO::Socket::INET->new(LocalPort => 6800, Type => SOCK_STREAM, Reuse => 1, Listen =>
use strict;
use IO::Socket;
my $server = IO::Socket::INET->new(LocalPort => 6800,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10) or die "$@\n";
my $client ;
while ( $client = $server->accept()) {
my $client_info;
while(<$client>) {
#last if /^\r\n$/;
print "received: '" . $_ . "'\n";
$client_info .= $_;
}
print $client "HTTP/1.0 200 OK\r\n";
print $client "Content-type: text/html\r\n\r\n";
print $client '<H1>Hello World(!), from a perl web server</H1>';
print $client '<br><br>you sent:<br><pre>' . $client_info . '</pre>';
close($client);
}
这是意料之中的。POST请求看起来像
use strict; use warnings; use autodie;
BEGIN { die "Untested code" }
package Local::HTTP::Request {
sub new {
my ($class, $method, $path, $version, $header_fields, $content) = @_;
...;
}
...; # accessors
sub new_from_fh {
my ($class, $fh) = @_;
local $/ = "\015\102"; # CRLF line endings
chomp(my $first_line = <$fh>);
my ($method, $path, $version) = ...; # parse the $first_line
# this cute little sub parses a single field incl. continuation
# and returns the next line as well.
my $parse_a_field = sub {
chomp(my $line = shift);
my ($name, $value) = split /:\s+/, $line, 2;
while(defined(my $nextline = <$fh>)) {
# handle line continuation
if ($nextline =~ s/^[ \t]//) {
chomp $nextline;
$value .= $nextline;
} else {
return $name, $value, $nextline;
}
}
};
my %fields;
my $line = <$fh>;
until ($line eq $/) {
(my $name, my $value, $line) = $parse_a_field->($line);
$fields{lc $name} = $value;
}
read $fh, my $content, $fields{"content-length"} // 0;
return $class->new( ... );
}
}
您在标题结束后终止处理,但数据在正文中
如果您真的想编写自己的HTTP服务器,那么应该从头中提取HTTP方法。如果是POST
,您可以查看内容长度
标题中的值,并读取该字节数:
my $request = Local::HTTP::Request->new_from_fh($client);
print $client "HTTP/1.0 200 OK", "\015\012";
print $client "Content-type: text/plain", "\015\012";
print $client "\015\012";
print $client "Request body:\n";
print $client $request->content;
更新后的问题: 如果您想构建一个生产HTTP服务器,那么您将经历一段糟糕的时光。这东西很难。请通读包含TCP服务器主题的内容。然后,您可以在此基础上实现HTTP的子集 还要通读CPAN上实现服务器的模块。即使不能在系统上编译模块,也可以使用纯Perl模块,或者找到可以重用的部分代码。CPAN的大部分可以在GPL许可下使用 如果你想这样做,就要做对。自己编写一个子例程来解析HTTP请求。这是一个不处理编码字段等的草图:
是的,我试图找到一个解决方法,例如接受第一个\r\n,然后在第二个出现时接受最后一个,但问题仍然存在。我试试看雷德
POST / HTTP/1.1
Header: Value
Data=Value
read $client, my $post_data, $content_length;
use strict; use warnings; use autodie;
BEGIN { die "Untested code" }
package Local::HTTP::Request {
sub new {
my ($class, $method, $path, $version, $header_fields, $content) = @_;
...;
}
...; # accessors
sub new_from_fh {
my ($class, $fh) = @_;
local $/ = "\015\102"; # CRLF line endings
chomp(my $first_line = <$fh>);
my ($method, $path, $version) = ...; # parse the $first_line
# this cute little sub parses a single field incl. continuation
# and returns the next line as well.
my $parse_a_field = sub {
chomp(my $line = shift);
my ($name, $value) = split /:\s+/, $line, 2;
while(defined(my $nextline = <$fh>)) {
# handle line continuation
if ($nextline =~ s/^[ \t]//) {
chomp $nextline;
$value .= $nextline;
} else {
return $name, $value, $nextline;
}
}
};
my %fields;
my $line = <$fh>;
until ($line eq $/) {
(my $name, my $value, $line) = $parse_a_field->($line);
$fields{lc $name} = $value;
}
read $fh, my $content, $fields{"content-length"} // 0;
return $class->new( ... );
}
}
my $request = Local::HTTP::Request->new_from_fh($client);
print $client "HTTP/1.0 200 OK", "\015\012";
print $client "Content-type: text/plain", "\015\012";
print $client "\015\012";
print $client "Request body:\n";
print $client $request->content;