flor~ has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I have a simple webserver that simply prints to the client, line by line, the file requested by the client.

On the other side, I have the client. The problem lies in the response that the client receives. If the requested file on the server side did not end with a \n character, the client will receive a portion of the file, but not the last line! (It follows that if the file did end with a \n, somewhere along the way, that newline will be eaten up; the client will receive the entire file but minus that last \n)

My question is, is there some way to indicate that the content is ended, without having the webserver to print out a newline regardless? I am building an automated test environment that must eventually match the response content with the original content. Among others, this is one of the reasons I'd not prefer to have extra \n's lying around. I've enclosed the corresponding client and server code are in readmore tags.

(Took out the testing of a valid request and other irrelevant stuff here).

The client:

my $remote = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => $ADDRESS, PeerPort => $PORT ) or die "cannot connect to server"; $remote->autoflush(1); open(OUT, ">out.txt"); print $remote "GET /theFile.txt HTTP/1.1\r\n"; print $remote "Host: $ADDRESS:$PORT\r\n"; print $remote "Connection: close\r\n"; print $remote "\r\n"; while( <$remote> ) { print OUT $_; } close $remote;

The webserver:

$| = 1; $server = IO::Socket::INET->new( Proto => 'tcp', LocalAddr => $ADDRESS, LocalPort => $SPORT, Listen => SOMAXCONN, Reuse => 1); die "can't setup server" unless $server; while ($client = $server->accept()) { $client->autoflush(1); my $request = <$client>; if ($request =~ m|^GET /(.+) HTTP/1.[0,1]|) { $file = $1; $size = -s $file; $_ = $file; ($ext) = /.+\.(\w+)/; $type = MimeTypes::GetType($ext); # some function to get mime +type print $client "HTTP/1.0 200 OK\r\n"; print $client "Connection: Keep-Alive\r\n"; print $client "Content-Type: $type\r\n"; print $client "Content-Length: $size\r\n"; print $client "\r\n"; open(FILE, $file); while(<FILE>) { print $client $_ ; } close(FILE); } close $client; }

Any guidance would be muchos appreciated!!

Replies are listed 'Best First'.
Re: webserver -- incomplete content prob
by iburrell (Chaplain) on Apr 08, 2004 at 19:56 UTC
    Your client is not an HTTP client. It completely ignores the Content-Length header which tells the length of the response body. That is the mechanism HTTP uses to indicate when the response ends. Instead, it reads the response by lines which fails as you discovered when the response does not end with a LF. The solution is to read the response header by line, parse out the Content-Length, and then read the body by blocks.

    Also, your client should not advertise HTTP 1.1 if it does not support it. Real HTTP will assume they can use stuff like chunked encoding and your client won't handle it.

    Finally, is there a reason you can't use LWP for the HTTP client? Or HTTP::Daemon for the server? Both of them handle all the nasty details of the HTTP protocol.

      Thanks for the swift reply =) I think I'll try using the read function then, instead of <FILE>.

      My test environment is actually for an HTTP proxy, so I want to have full control over exactly what the server and client send to each other. For example, LWP uses HTTP 1.0, I want to be able to send 1.1 as well. (For the above sample code, I took out the more involved parsing, including chunks and stuff.)