Simple perl-based WWW-server hangs: what am I doing wrong?

Simple perl-based WWW-server hangs: what am I doing wrong?

Post by Ron Newm » Sat, 29 Apr 1995 04:00:00



I'm trying to write a simple-minded WWW server in perl, which simply
echoes back all the protocol that the client sends. The purpose is
to display the MIME headers and to see exactly what gets sent when a form
or image-map is invoked.

Unfortunately, my perl script is* whenever the HTTP request type
is "POST" and the Content-Length: MIME header is present.  I'm*
on the line

      read(NS, $line, $length); # this hangs, why?

It hangs even if I change the "$length" to 1 !
But it doesn't hang if I comment it out and uncomment the following line

      # $line = <NS>;  # this doesn't hang

I'm misunderstanding either perl or the HTTP protocol.  Which is it?

To test this, run the perl script (appended below) on the test form
(also appended below).  Invoke the button marked "prostrate".

-------------------
#!/usr/bin/perl

require 'sys/socket.ph';

$sockaddr = 'S n a4 x8';

#serve TCP port 7999 unless a different one is specified on command line
$proto = (getprotobyname('tcp'))[2];
$port = $ARGV[0] || 7999;
$port = pack($sockaddr, &AF_INET, $port, "\0\0\0\0");

socket(S, &AF_INET, &SOCK_STREAM, $proto) || die "Can't open socket: $!";
bind(S, $port) || die "Can't bind socket: $!";
listen (S, 5);

while(1) {
   accept(NS, S);
   select (NS);
   $| = 1;

   # send standard HTTP "OK" reply
   print "HTTP/1.0 200 OK\r\n";
   print "Content-type: text/plain\r\n\r\n";

   # read and echo HTTP command request; save request-type away for later use
   ($reqtype) = split(/ /, $_ = <NS>);
   print;

   # read and echo MIME headers; watch for Content-Length: header
   while (<NS>) {
      print;
      /^Content-Length:\s*(.*)\r$/i && ($length = $1);
      last if /^\r$/; # blank line ends MIME headers
      }

   if ($length) {
      # Content-Length: header found; read the specified number of bytes
      read(NS, $line, $length); # this hangs, why?
      # $line = <NS>;  # this doesn't hang
      print "$line\r\n";
      }

   elsif (($reqtype eq "PUT") || ($reqtype eq "POST")) {
      # no Content-Length: header, so look for terminating line
      while (<NS>) {
         last if /^.\r$/;  # line containing only a period terminates input
         print;
         }
      }
   close NS;
   }

-------------------------
<html>
<head>
<title>Form Test Page</title>

</head>

<body>
<h1>Form test page</h1>
<form action="http://localhost:7999/form/action" method="POST"><br>
A text field follows.
<input type=text name=teggst value=the-text size=30><br>
A password field follows.
<input type=password name=passwd value=the-password size=25><br>
A checkbox field follows.
<input type=checkbox name=czechbox value=prague><br>
Two buttons follow.
<input type=submit value=prostrate> <input type=reset value="forget it!">
</body>
</html>

-----------------
--

Web: http://www.veryComputer.com/:8001/people/rnewman/home.html
(I speak only for myself, not for any part of MIT.)

 
 
 

Simple perl-based WWW-server hangs: what am I doing wrong?

Post by Marc Horowi » Sat, 29 Apr 1995 04:00:00


I've been working with Ron on this, and I've tracked it down to a perl
bug.  This script demonstrates the problem:

    #!/afs/athena/contrib/perl/perl

    $port = $ARGV[0] || 7999;

    require 'sys/socket.ph';
    require 'netinet/in.ph';

    socket(S,&AF_INET,&SOCK_STREAM,&IPPROTO_TCP) || die "socket S: $!\n";
    bind(S, pack("S n C4 x8", &AF_INET, $port, 0,0,0,0)) || die "bind: $!\n";

    socket(C,&AF_INET,&SOCK_STREAM,&IPPROTO_TCP) || die "socket C: $!\n";

    listen(S, 5) || die "listen: $!\n";

    connect(C, pack("S n C4 x8", &AF_INET, $port, 127,0,0,1))
        || die "connect: $!\n";

    accept(F, S) || die "accept: $!\n";

    select((select(C),$|=1)[0]);

    print C "one  \r\ntwo  \r\n";

    $in = <F>;
    print "--> ",$in;

    print C "three\r\nfour\r\n";

    read(F, $in, 7) || next;
    print "--> ",$in;

    $in = <F>;
    print "--> ",$in;

    $in = <F>;
    print "--> ",$in;

perl4 prints

--> one  
--> three
--> two  
--> four

perl5 prints

--> one  
--> two  
--> three
--> four

The latter is correct.  Since perl5 does the right thing, it's not a
big deal, but this could conceiveably still affect some people.

If this is really an ambiguity in perl4, that would be interesting to
know.

                Marc

 
 
 

Simple perl-based WWW-server hangs: what am I doing wrong?

Post by Jutta Degen » Sun, 30 Apr 1995 04:00:00



> I've been working with Ron on this, and I've tracked it down
> to a perl bug.

[... sample code deleted ...]

Quote:> If this is really an ambiguity in perl4, that would be
> interesting to know.

Tracing Ron's script showed that the "while (<NS>)" did a (presumably
stdio-buffered) read() of 4096 bytes, and the "read" on the socket
descriptor later called recvfrom().  That was not what was needed---
it should have done an fread() and should have found whatever was in
stdio's buffer.

Looking at the 4.0 Perl code, eval.c, line 1496 or so, I see

    int
    eval(arg,gimme,sp)
    register ARG *arg;
    int gimme;
    register int sp;
    {
[...]
        case O_READ:
        case O_SYSREAD:
[...]
        STR_GROW(st[2], anum+maxarg+1), (tmps = str_get(st[2]));  /* sneaky */
        if (optype == O_SYSREAD) {
            anum = read(fileno(stab_io(stab)->ifp), tmps+maxarg, anum);
        }
        else
    #ifdef HAS_SOCKET
        if (stab_io(stab)->type == 's') {
            argtype = sizeof buf;
[ X ]       anum = recvfrom(fileno(stab_io(stab)->ifp), tmps+maxarg, anum, 0,
            buf, &argtype);
        }
        else
    #endif
            anum = fread(tmps+maxarg, 1, anum, stab_io(stab)->ifp);
[...]
    }

The bit marked [ X ], apparently, is where perl 4.0 takes a wrong
turn---ignoring whatever parts of the message might have still been
buffered within stdio.  <>, in contrast, goes through str_gets(),
which uses getc() and stdio buffering, regardless of the flavor of
stream used.


 
 
 

1. AIX, sar and perl (what am I doing wrong?)

I have the following perl script. Which is supposed to execute
the UNIX 'sar' command, descard any header information from the
sar output and save the performance data in an output file.

The script works, but it never saves data to the output file
"sar.out" until the close(SARF) gets executed. What should I
do to save data to the output file after every sample (line)?

Any ideas?? by the way, I am running perl 5.004_04 under AIX
4.3.2.

Thanks,
Juan

----- script starts here -----
#!/usr/bin/perl

use FileHandle;

sub collect_sar
{

  open(SARF,">$outf");
  autoflush SARF;


  autoflush SAR;

  while(<SAR>) {
    if ( /^\d\d:\d\d:\d\d\s+\d+\s+\d+\s+\d+\s+\d+/ ) {
      print SARF $_;
    }
  }
  close(SAR);
  close(SARF);

&collect_sar(15,5,"sar.out");

----- script ends here -----

Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.

2. kppp security (bugs?)

3. CDE 1.3: Hangs/Core Dumps for automounted logins: What am I doing wrong?

4. Cobol for Linux

5. non-forking TCP-server - what am i doing wrong?

6. Reduce Ethernet MTU

7. Dual Homed Linux - what am I doing wrong?

8. Joystick under EMU

9. Am I doing something wrong?? - (SAMBA)

10. One more question - What am I doing wrong?

11. KNode (No Caching) - What am I doing no wrong

12. gethostbyname misbehavior - what am i doing wrong.

13. What am I doing wrong?????