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

Hi, I am designing a primitive web server using the IO::Socket module and am trying to read the request headers from the client. I have been successful in reading in the first header:"GET /index.html HTTP/1.1". I have accomplished this by issuing a statement like this:
#!/usr/bin/perl -w + use strict; use IO::Socket; my $socket_server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 7788, Reuse => 1, Proto => 'tcp' ) or die "$!"; my ($c, $request_headers); while ($c = $socket_server->accept()) { $c->autoflush(1); my $request_headers = <$c>; print $request_headers; }
This sample is simplified for this question. As I mentioned, with this code, I can easily grab the first line of the headers. However, I want to grab the rest of the headers. For example, I need to grab the "Host: somehost.com" header, which is typically the second line. Thinking that I could treat this like any other file handel, I replaced the contents of the while loop with this:
$c->autoflush(1); my @request_headers = <$c>; # line 3 for $header_line (@request_headers) { print $header_line; }
However, line 3 causes the web browser to stall. I am guessing that the program doesn't know when all of the headers have been displayed and just hangs. I have tried a variety of different things to try to get the program to stop reading once the headers have been displayed, but I have had no success. I would be overjoyed if someone has any suggestions regarding this problem. Thank you for reading this, Joe

Replies are listed 'Best First'.
Re: IO::Socket Get Headers
by ikegami (Patriarch) on Oct 02, 2004 at 02:57 UTC

    my @request_headers = <$c>;
    reads until the end of the file, pushing each line onto the array. However, you're suppose to stop reading when you see CRLFCRLF. To read just the next line, do:
    my $next_line = <$c>;

    You're reinventing the wheel, though. (And you're already doing things wrong, like reading too far, and not setting $/ to "\015\012".) There's already at least one mini perl httpd you can use, HTTP::Daemon, and I think it even comes standard with perl.

      Hi, thanks. That's just the info I needed and the solution was easier than I was making it to be. That problem stumped me for hours. I'll look into the HTTP::Deamon module as a future alternative. Thanks again for your help. Joe
      Hi, I am having some luck based on the suggestions that you gave me. However, what do you mean by:
      setting $/ to "\015\012"
      Also, if the code that you provided reads only one line at a time, how do I test for the condition of having two control feeds? Forgive me for the ignorant questions. Joe

        If you check the spec, you'll notice HTTP header lines are terminated by CRLF. Your code checks for only LF. 015 is the octal value for CR, 012 is the octal value for LF. ("\r\n" isn't good cause they're not always CR and LF.)

        You can tell you received two CRLF in a row when reading a line at a time by checking for a blank line.

        my @headers; { local $/ = "\015\012"; while (<IN>) { chomp; last if $_ eq ''; push(@headers, $_); } } my $request_line = shift(@headers);

        That handles HTTP/1.0 and HTTP/1.1 requests, but I don't know about HTTP/0.9 requests.