This is to be expected. A POST request looks like
POST / HTTP/1.1
Header: Value
Data=Value
You terminate processing after the end of the header, but the data is in the body!
If you really want to write your own HTTP server, then you should extract the HTTP method from the header. If it is POST
, you can look at the value from the Content-length
header, and read that number of bytes:
read $client, my $post_data, $content_length;
WRT the updated question:
If you want to build a production HTTP server, you are going to have a bad time. This stuff is difficult. Please read through perlipc
which covers the topic of TCP servers. You can then implement a subset of HTTP on top of this.
Also read through the modules on CPAN that implement servers. Even if you cannot compile modules on your system, you may be able to use pure-Perl modules, or may find parts of code that you can reuse. Large parts of CPAN can be used under a GPL license.
If you want to do this, do it right. Write yourself a subroutine that parses a HTTP request. Here is a sketch that doesn't handle encoded fields etc.:
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( ... );
}
}
Then in your accept
loop:
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;